package com.apes.fn.server.servicePlan.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.crm.business.model.InsuranceCompany;
import com.apes.crm.business.model.InsuranceCompanyDetail;
import com.apes.fn.business.carAccident.modle.CarAccident;
import com.apes.fn.business.carAccident.modle.CarEvaluation;
import com.apes.fn.business.carAccident.repository.CarAccidentRepository;
import com.apes.fn.business.carAccident.repository.CarEvaluationRepository;
import com.apes.fn.business.fixedLoss.modle.LossAssessmentGoods;
import com.apes.fn.business.fixedLoss.modle.LossQuotation;
import com.apes.fn.business.fixedLoss.modle.LossQuotationItem;
import com.apes.fn.business.fixedLoss.repository.LossAssessmentGoodsRepository;
import com.apes.fn.business.fixedLoss.repository.LossQuotationRepository;
import com.apes.fn.business.fixedLoss.service.FixedLossToForeign;
import com.apes.fn.business.fixedLoss.service.LossQuotationService;
import com.apes.fn.crm.customer.FnApiService;
import com.apes.fn.crm.customer.FnAppCustomerService;
import com.apes.fn.crm.customerExpand.FnCustomerExpand;
import com.apes.fn.crm.customerExpand.PickUpTypeF;
import com.apes.pi.model.Timestamp;
import com.apes.pi.repository.TimestampRepository;
import com.apes.scm.masterdata.enumeration.model.BusinessParam;
import com.apes.scm.masterdata.enumeration.repository.BusinessParamRepository;
import com.apes.fn.mdm.purchase.PurchasingGroup;
import com.apes.fn.mdm.purchase.PurchasingGroupRepository;
import com.apes.fn.pi.fnCommunal.FnCommunalService;
import com.apes.fn.scm.commodityInquiry.model.CommodityInquiryItem;
import com.apes.fn.scm.commodityInquiry.model.ExternalInquiry;
import com.apes.fn.scm.commodityInquiry.repository.ExternalInquiryRepository;
import com.apes.fn.scm.commodityInquiry.service.CommodityInquiryOrderService;
import com.apes.fn.scm.merchant.settlement.service.FeeRateService;
import com.apes.fn.scm.retailOrder.model.RetailOrder;
import com.apes.fn.scm.retailOrder.service.tc.TCService;
import com.apes.fn.scm.used.model.Used;
import com.apes.fn.scm.used.model.UsedStore;
import com.apes.fn.scm.used.model.UsedStoreItem;
import com.apes.fn.scm.used.repository.UsedRepository;
import com.apes.fn.server.pickUpCar.model.PickUpCar;
import com.apes.fn.server.pickUpCar.repository.PickUpCarRepository;
import com.apes.fn.server.pickUpCar.service.PickUpCarService;
import com.apes.fn.server.productReceive.ProductReceive;
import com.apes.fn.server.productReceive.ProductReceiveItem;
import com.apes.fn.server.productReceive.ProductReceiveRepository;
import com.apes.fn.server.productRequire.*;
import com.apes.fn.server.productReturn.ProductReturn;
import com.apes.fn.server.productReturn.ProductReturnItem;
import com.apes.fn.server.servicePlan.model.*;
import com.apes.fn.server.servicePlan.repository.*;
import com.apes.fn.server.servicePlan.service.planNodeService.AuditNodeService;
import com.apes.fn.server.servicePlan.service.planNodeService.QualityDetailService;
import com.apes.fn.server.transferVehicle.model.InnerPickDeliveryUpCar;
import com.apes.fn.server.transferVehicle.model.InnerPickDeliveryUpCarItem;
import com.apes.fn.server.transferVehicle.service.InnerPickDeliveryUpCarService;
import com.apes.fn.server.workOrder.model.MaintenanceOrder;
import com.apes.fn.server.workOrder.repository.MaintenanceOrderRepository;
import com.apes.fn.server.workOrder.service.MaintenanceOrderService;
import com.apes.fn.tms.repository.SiteRepository;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.Model;
import com.apes.framework.jpa.logger.ApesLoggerService;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.event.Listener;
import com.apes.framework.plugin.outbox.OutboxEventService;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.plugin.outbox.OutboxSubscriberService;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.plugin.soe.metadata.BusinessAttributeValue;
import com.apes.framework.plugin.soe.store.database.repository.BusinessAttributeValueRepository;
import com.apes.framework.util.*;
import com.apes.pi.service.PiManager;
import com.apes.scm.account.account.model.InventoryBatch;
import com.apes.scm.account.account.model.Stock;
import com.apes.scm.account.account.repository.InventoryBatchRepository;
import com.apes.scm.account.account.repository.StockRepository;
import com.apes.scm.account.account.service.ProductAccountService;
import com.apes.scm.contract.model.Contract;
import com.apes.scm.contract.repository.ContractRepository;
import com.apes.scm.masterdata.car.model.CarConfiguration;
import com.apes.scm.masterdata.car.model.CarLabel;
import com.apes.scm.masterdata.car.model.CarModel;
import com.apes.scm.masterdata.car.model.CarServiceLevel;
import com.apes.scm.masterdata.car.repository.CarConfigurationRepository;
import com.apes.scm.masterdata.car.service.CarServiceLevelService;
import com.apes.scm.masterdata.contrast.model.ContrastPartyCode;
import com.apes.scm.masterdata.contrast.repository.ContrastPartyCodeRepository;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.finance.model.CooperateType;
import com.apes.scm.masterdata.finance.model.CrossIC;
import com.apes.scm.masterdata.finance.repository.CrossICRepository;
import com.apes.scm.masterdata.frame.model.Channel;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.frame.model.Store;
import com.apes.scm.masterdata.frame.repository.ChannelRepository;
import com.apes.scm.masterdata.frame.repository.DeptRepository;
import com.apes.scm.masterdata.frame.repository.StoreRepository;
import com.apes.scm.masterdata.frame.service.StoreService;
import com.apes.scm.masterdata.party.model.AccessProvider;
import com.apes.scm.masterdata.party.model.CompanyEntry;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.AccessProviderRepository;
import com.apes.scm.masterdata.party.repository.CompanyEntryRepository;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.masterdata.party.service.PartyRoleService;
import com.apes.scm.masterdata.product.model.*;
import com.apes.scm.masterdata.product.repository.*;
import com.apes.scm.masterdata.stock.model.Location;
import com.apes.scm.masterdata.stock.model.PhyDepot;
import com.apes.scm.masterdata.stock.repository.LocationRepository;
import com.apes.scm.masterdata.stock.service.LocationService;
import com.apes.scm.pur.purchaseOrder.model.PurchaseOrder;
import com.apes.scm.pur.purchaseOrder.repository.PurchaseOrderRepository;
import com.apes.scm.rbac.model.Post;
import com.apes.scm.rbac.model.User;
import com.apes.scm.rbac.repository.PostRepository;
import com.apes.scm.rbac.repository.UserRepository;
import com.apes.scm.stock.transfer.model.Pick;
import com.apes.scm.voucher.service.VoucherType;
import org.bson.Document;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;

/**
 * Creator: zouyc
 * CreateDate: 2020-01-02 14:14
 * Description:
 **/
@Service("servicePlanceService")
public class ServicePlanceService extends AbstractPlan {

    List<BusinessParam> findAllByQueryKey = SpringManager.getBean(BusinessParamRepository.class).findAllByQueryKey("systemEnvironment");
    List<BusinessParam> findBaturuSupplier = SpringManager.getBean(BusinessParamRepository.class).findAllByQueryKey("baturuSupplier");
    @Autowired
    private ServicePlanRepository servicePlanRepository;
    @Autowired
    private StockRepository stockRepository;
    @Autowired
    private ProductAccountService productAccountService;
    @Autowired
    private ServiceToForeign serviceToForeign;
    @Autowired
    private DeptRepository deptRepository;
    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private ServeCategoryRepository serveCategoryRepository;
    @Autowired
    private EnumerationRepository enumerationRepository;
    @Autowired
    private ProductUomRepository productUomRepository;
    @Autowired
    private LocationRepository locationRepository;
    @Autowired
    private ServicePlanItemRepository servicePlanItemRepository;
    @Autowired
    private PostRepository postRepository;
    @Autowired
    private ServicePlanDao servicePlanDao;
    @Autowired
    private PiManager piManager;
    @Autowired
    private BusinessAttributeValueRepository businessAttributeValueRepository;
    @Autowired
    private OutboxSubscriberService outboxSubscriberService;
    @Autowired
    private UsedRepository usedRepository;
    @Autowired
    private SantouliubiService santouliubiService;
    @Autowired
    private ApesLoggerService apesLoggerService;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private LossQuotationRepository lossQuotationRepository;
    @Autowired
    private MaintenanceOrderService maintenanceOrderService;
    @Autowired
    private MaintenanceOrderRepository maintenanceOrderRepository;
    @Autowired
    private ContractRepository contractRepository;
    @Autowired
    private AuditNodeService auditNodeService;
    @Autowired
    private ProductRequireRepository productRequireRepository;
    @Autowired
    private PurchaseOrderRepository purchaseOrderRepository;
    @Autowired
    private ProductRequireExpandRepository productRequireExpandRepository;
    @Autowired
    private ProductReceiveRepository productReceiveRepository;
    @Autowired
    private ProductNegativeSellingRepository productNegativeSellingRepository;
    @Autowired
    private DistributedLock distributedLock;
    @Autowired
    private GetPriceLoggerService getPriceLoggerService;
    @Autowired
    private QualityDetailService qualityDetailService;
    @Value("${apes.switched:false}")
    private Boolean switched;
    public static final String CONST_REQUIRE_COLLECTION_NAME = "serviceRequireGoods";
    public static final String CONST_ERROR_MSG_COLLECTION_NAME = "serviceErrorMsg";
    public static final String FD_COOPERATION_ID = "distribution";
    public static final List<String> PLATFORM_OUT_ORDER = Arrays.asList("富登","师人订制");//不要更改顺序
    public static final Map<String,List<String>> PLAN_SIMPLE_STATE =
            mapper("create",Arrays.asList("create","goBack","toTechAudit","techAudit","backTechAudit","toPriceAudit","priceAudit","backPriceAudit","inquiryFinish","backInquiry"),
                    "submission",Arrays.asList("submission"),
                    "confirm",Arrays.asList("confirm"),
                    "qualityTest",Arrays.asList("qualityTest"),
                    "receivables",Arrays.asList("receivables"),
                    "termination",Arrays.asList("termination")
                    );


//    private SimpleRequest request;

    public ServicePlan outerCreateOrUpdate(SimpleRequest simpleRequest){
        ServicePlan servicePlan = simpleRequest.getO(ServicePlan.class);
        return save(servicePlan);
    }

    public ServicePlan outerCreateOrUpdate(ServicePlan servicePlan){
        if ("LossQuotation".equals(servicePlan.getSourceBusinessType())){
            //工单终止,判断明细商品终止标记 (Collectors.toCollection(ArrayList::new));
            List<Product> products = servicePlan.getServicePlanItems().stream().map(
                    item -> {
                        if (item.getTerminationDate() != null) {
                            return item.getProduct();
                        }else {
                            return null;
                        }
                    }
            ).collect(Collectors.toList());
            try {
                SpringManager.getBean(LossQuotationService.class).writeBackLossQuotation(products,
                        servicePlan.getSourceFrom());
            } catch (Exception e) {
                throw new RuntimeException("清空定损报价的服务方案号失败!!!");
            }
        }
        return save(servicePlan);
    }

    /**
     * 新增方案
     * @param simpleRequest
     * @return
     */
    public ServicePlan create(SimpleRequest simpleRequest){
        ServicePlan servicePlan = simpleRequest.getO2(ServicePlan.class);
        String branchId = getSession(simpleRequest)==null? null:getSession(simpleRequest).getBranchId();
        return getPlanDept(servicePlan, branchId);
    }

    private ServicePlan getPlanDept(ServicePlan servicePlan, String branchId) {
        servicePlan.setBusinessType(StringUtil.toLowerCaseFirst(ServicePlan.class.getSimpleName()));
        servicePlan.setBusinessTypeName("服务方案");
        dealMDDetail_Create(servicePlan,branchId);
//        savePickUpTypes(servicePlan.getFnCustomerExpand());
        if(servicePlan.getPlanType() == null) servicePlan.setPlanType("common");
        // 回写方案明细状态
        servicePlan.getServicePlanItems().forEach(item -> {
            if (Objects.isNull(item.getState())) item.setState("create");  // 只有新增的明细状态为create，其他原有的保留
            if (Objects.isNull(item.getWorkState())) item.setWorkState("wait");
        });
        return save(servicePlan);
    }

    public ServicePlan localCreate(SimpleRequest simpleRequest){
        ServicePlan servicePlan = simpleRequest.getO2(ServicePlan.class);
        if (servicePlan.getConfirmDate()!=null)throw new RuntimeException("方案已确认,不允许修改");
        servicePlan.setFnCustomerExpand(findFnCustomerExpandAndSave(servicePlan.getSaleDept(),simpleRequest.getJO().getJSONObject("customer"),simpleRequest.getJO().getJSONObject("customerCar")));
        localCreateCheck(servicePlan);
        initPlan(servicePlan);
//        Object mapped = MapUtil.mapped(servicePlan);
        return servicePlan;
    }

    private void localCreateCheck(ServicePlan servicePlan) {
        servicePlan.getServicePlanItems().forEach(item ->{
            if (PLATFORM_OUT_ORDER.contains(item.getProduct().getBrand().getName()))
                throw new RuntimeException(item.getProduct().getName()+" 商品属于定制款商品,请前往黑盒商城下单! !");
        });
    }

    private void initPlan(ServicePlan servicePlan) {
        servicePlan.setState("create");
        //手动做单，默认零售，渠道10
        Channel channel = SpringManager.getBean(ChannelRepository.class).findOne("10");
        if (servicePlan.getServeType()!=null&&servicePlan.getServeType().getCode().equals("B"))servicePlan.setSaleDept(servicePlan.getBelongDept());
        if(channel == null) throw new RuntimeException("渠道定义有误，无零售渠道");
        servicePlan.setChannel(channel);
        //当前操作去做保存
        try {
            if(servicePlan.getFnCustomerExpand()==null)
                servicePlan.setFnCustomerExpand(findFnCustomerExpandAndSave(servicePlan.getSaleDept(), new JSONObject(servicePlan.getCustomer()),new JSONObject(servicePlan.getCustomerCar())));
        }catch (Exception e){
            throw new RuntimeException(e.getMessage());
        }
        if(!servicePlan.getBelongDept().getId().equals(servicePlan.getSaleDept().getId())){
            servicePlan.setPlanType("allAssist");
        }
    }


    public List<Enumeration> obtainPickUpType(SimpleRequest req){
        JSONObject jo = req.getJO();
        String deptId = jo.getString("deptId");
        String carlicense = jo.getString("carlicense");
        if(deptId == null || carlicense == null) return null;
        Dept dept = deptRepository.findOne(deptId);
        FnCustomerExpand fnCustomerExpand = null;
        fnCustomerExpand = findValidServiceFnCustomerExpand(dept,carlicense);
        return fnCustomerExpand == null ? null : fnCustomerExpand.getPickUpTypeF() == null ? null : fnCustomerExpand.getPickUpTypeF().stream().map(PickUpTypeF::getPickUpType).collect(Collectors.toList());
    }



    public Page<ServicePlan> findAllQualityTest(SimpleRequest simpleRequest){
        List<Map> fillters = simpleRequest.get("condition");
        fillters.add(MapUtil.mapper("field", "state", "value", "termination", "operator", "NE"));
        fillters.add(MapUtil.mapper("field", "finishWork", "value", true, "operator", "EQ"));
        Page page = servicePlanRepository.findAll(JpaDsl.toCriteria(fillters),PageRequest.of(simpleRequest.get("page"),simpleRequest.get("size")));
        return page;
    }

    /**
     * 返回app会员和车辆的json格式数据
     * customerCar  customer
     * @param carId
     * @param customerId
     * @return
     */
    public Map findCustomerCarAndCustomerInfo(String carId,String customerId){
        JSONObject customerCar =
                (JSONObject)this.invoke("fn.customerCar.findOne",MapUtil.mapper("id",carId));
        if(customerCar == null || customerCar.getString("id") == null || "".equals(customerCar.getString("id").trim())){
            throw new RuntimeException("未找到车辆信息");
        }
        JSONObject customer = (JSONObject)this.invoke("fn.customer.findOne",MapUtil.mapper("id",customerId));
        if(customer == null || customer.getString("id") == null || !customerId.equals(customer.getString("id"))){
            throw new RuntimeException("查无此会员");
        }
        return MapUtil.mapper("customerCar",customerCar,"customer",customer);
    }

    public ServicePlan workOrderCreate(SimpleRequest request){
        ServicePlan servicePlan = request.getO(ServicePlan.class);
        return save(servicePlan);
    }

    public ServicePlan update(SimpleRequest simpleRequest){
        ServicePlan servicePlan = simpleRequest.getO2(ServicePlan.class);
        if (servicePlan.getConfirmDate()!=null)throw new RuntimeException("方案已确认,不允许修改");
        changeItemWorkState(servicePlan);
        localCreateCheck(servicePlan);
        return save(servicePlan);
    }
    public ServicePlan changeSaler(SimpleRequest simpleRequest){
        String id = simpleRequest.get("id");
        ServicePlan servicePlan = servicePlanRepository.findOne(id);
        ServicePlan servicePlan2 = simpleRequest.getO(ServicePlan.class);
        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            servicePlan2.getServicePlanItems().forEach(servicePlanItem2 ->{
                if (Objects.equals(servicePlanItem2.getId(), servicePlanItem.getId())){
                    servicePlanItem.setMainSaler(servicePlanItem2.getMainSaler());
                    servicePlanItem.setSupSaler(servicePlanItem2.getSupSaler());
                }
            });
        });
        return updateOnly(servicePlan);
    }

    public ServicePlan updateServe(ServicePlan servicePlan){
        return save(servicePlan);
    }


    public ServicePlan updateOnly(ServicePlan servicePlan){
        servicePlan.setUpdateDate(new Date());
        return servicePlanRepository.saveAndFlush(servicePlan);
    }

    private void changeItemWorkState(ServicePlan servicePlan){
        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            if (Objects.isNull(servicePlanItem.getWorkState())) servicePlanItem.setWorkState("wait");
        });
    }


    /**
     * 设置做单门店，公司
     * 如果无门店，从做单的去门店
     * 公司是销售门店的公司
     * @param servicePlan
     * @param
     */
    private void dealMDDetail_Create(ServicePlan servicePlan,String branchId){
        if(servicePlan.getServiceDept() == null)    //服务门店
            servicePlan.setServiceDept(deptRepository.findOne(branchId));
        if(servicePlan.getBelongDept() == null)     //单据所属门店门店
            servicePlan.setBelongDept(deptRepository.findOne(branchId));
        if(servicePlan.getSaleDept()==null)         //销售门店门店
            servicePlan.setSaleDept(deptRepository.findOne(branchId));
        //设置单据公司
        servicePlan.setCompany(servicePlan.getBelongDept().getCompany()); //单据公司是销售门店的公司
    }

    private Map<String,ServeType> categoriesCache = null;
    /**
     * 处理从老框架获取来的明细值
     * company organization uom location
     */
    private void dealItemDetail(ServicePlan servicePlan){
        for(ServicePlanItem servicePlanItem : servicePlan.getServicePlanItems()) {
            if(servicePlanItem.getMainSaler() != null
                    && servicePlanItem.getSupSaler() != null
                    && servicePlanItem.getMainSaler().getId().equals(servicePlanItem.getSupSaler().getId())){
                throw new RuntimeException("主辅销不能相同");
            }
            // 所有从这产生的都是普通类型的
            servicePlanItem.setAssistType(
                    servicePlanItem.getAssistType() != null ?  servicePlanItem.getAssistType() : businessAttributeValueRepository.findOne("ServicePlanItem.assistType.normal")
            );

            //提交后不再改变的参数
            if(servicePlan.getSubmissionDate() == null){
                ServeTypeRepository typeRepository = SpringManager.getBean(ServeTypeRepository.class);
                String classId = servicePlanItem.getProduct().getClassify().getId();
                if (categoriesCache == null) {
                    categoriesCache = new HashMap<>();
                    serveCategoryRepository.findAll().forEach(serveCategory -> {
                        ServeType serveType = serveCategory.getServeType();
                        if(serveType==null)return;
                        String id = serveType.getId();
                        categoriesCache.put(serveCategory.getId(), typeRepository.findOne(id));
                    });
                }
                ServeType serveType = categoriesCache.get(classId);
                if(serveType == null){
                    categoriesCache = null;
                    throw new RuntimeException("商品主数据缺失（品类），商品：" + servicePlanItem.getProduct().getName());
                };
                servicePlanItem.setServeType(serveType);
            }
        }
    }
    //集群环境 没多大用 但好歹有点用
    @OutboxSubscriber(name = "品类服务类型缓存更新")
    private void deleteCache(ServeCategory category){
        Map<String,ServeType> hashMap = new HashMap<>();
        serveCategoryRepository.findAll().forEach(serveCategory -> {
            ServeType serveType = serveCategory.getServeType();
            if(serveType==null)return;
            String id = serveType.getId();
            hashMap.put(serveCategory.getId(), serveType);
        });
        categoriesCache = hashMap;
    }

    private void deleteCategoriesCache(SimpleRequest request){
        categoriesCache = null;
    }

    /**
     * 判断是否低于限价级别，不允许提交
     */
    private void checkPriLimitLevel(String priLimitLevel,ServicePlanItem servicePlanItem) {
        switch (priLimitLevel){
            case "1": //突破最低现价
                if(servicePlanItem.getPftPriceUnit()<servicePlanItem.getFloorPrice())
                    throw new RuntimeException("销售价不得低于岗位限价，商品：" + servicePlanItem.getProduct().getName());
                break;
            case "2": //突破最低现价
                if(servicePlanItem.getPftPriceUnit()<servicePlanItem.getCsoPriceLimit())
                    throw new RuntimeException("销售价不得低于岗位限价，商品：" + servicePlanItem.getProduct().getName());
                break;
            case "3"://销售总监
                if(servicePlanItem.getPftPriceUnit()<servicePlanItem.getCsoPriceLimit())
                    throw new RuntimeException("销售价不得低于岗位限价，商品：" + servicePlanItem.getProduct().getName());
                break;
            case "4"://店长
                if(servicePlanItem.getPftPriceUnit()<servicePlanItem.getShopOwnerPriceLimit())
                    throw new RuntimeException("销售价不得低于岗位限价，商品：" + servicePlanItem.getProduct().getName());
                break;
            case "5"://店员
                if(servicePlanItem.getPftPriceUnit()<servicePlanItem.getClerkPriceLimit())
                    throw new RuntimeException("销售价不得低于岗位限价，商品：" + servicePlanItem.getProduct().getName());
                break;
                default:
                    throw new RuntimeException("miss：岗位限价级别有误，请联系管理员查看");
        }
    }

    /**
     * 是否低于岗位限价
     * @param priLimitLevel
     * @param servicePlanItem
     * @return
     */
    private boolean isLowerThanPriLimitLevel(String priLimitLevel,ServicePlanItem servicePlanItem){
        switch (priLimitLevel){
            case "1": //突破最低现价
                if(servicePlanItem.getPftPriceUnit()<servicePlanItem.getFloorPrice())
                    return true;
                break;
            case "2": //突破最低现价
                if(servicePlanItem.getPftPriceUnit()<servicePlanItem.getCsoPriceLimit())
                    return true;
                break;
            case "3"://销售总监
                if(servicePlanItem.getPftPriceUnit()<servicePlanItem.getCsoPriceLimit())
                    return true;
                break;
            case "4"://店长
                if(servicePlanItem.getPftPriceUnit()<servicePlanItem.getShopOwnerPriceLimit())
                    return true;
                break;
            case "5"://店员
                if(servicePlanItem.getPftPriceUnit()<servicePlanItem.getClerkPriceLimit())
                    return true;
                break;
            default:
                throw new RuntimeException("miss：岗位限价级别有误，请联系管理员查看");
        }
        return false;
    }


    public ServicePlan save(ServicePlan servicePlan){
        checkItemUnique(servicePlan);
        dealItemDetail(servicePlan);
        checkCarInfo(servicePlan);
        servicePlan.computeSum();

        if (Objects.equals("LossQuotation",servicePlan.getSourceBusinessType())&&servicePlan.getSourceFrom()!=null) {

            LossQuotation lossQuotation = lossQuotationRepository.findOne(servicePlan.getSourceFrom());

            if (Objects.equals("B",lossQuotation.getOrderType().getCode())
                    && Arith.round(servicePlan.getClaimAmount(),1) != Arith.round(servicePlan.getSalesAmount(),1)) {
                throw new RuntimeException("服务单金额不等于定损总金额，请调整服务单金额!!!");
            }
        }
        servicePlan.setPickUpTypeS(servicePlan.getPickUpTypeS());
        String getCarType = SpringManager.getBean(LossQuotationService.class).getGetCarType(servicePlan);
        servicePlan.setGetCarType(getCarType);
        servicePlan.setCarLiscence(servicePlan.getFnCustomerExpand().getCarLicense());
//        List<ServicePlanItem> servicePlanItems = servicePlan.sortFotErp(servicePlan.getServicePlanItems());
        List<ServicePlanItem> servicePlanItems = servicePlan.getServicePlanItems();
        for (int i = 0; i < servicePlanItems.size(); i++) {
            ServicePlanItem servicePlanItem = servicePlanItems.get(i);
            servicePlanItem.setSort(i);
            if (servicePlan.getSubmissionDate()!=null) servicePlanItem.changerInquirySelectFlag(servicePlanItem.getServiceStateInt());
        }
        servicePlan = servicePlanRepository.saveAndFlush(servicePlan);
        return servicePlan;
    }

    public void checkCarInfo(ServicePlan servicePlan) {
        //回写接车时间接车人
        if (servicePlan.getGetCarInfo()==null||servicePlan.getGetCarInfo().equals("--")){
            servicePlan.insertGetCarInfoForMap(carInformation(new JSONObject(servicePlan.getCustomerCar()),servicePlan.getBelongDept()));
        }
//        //增加接车人和时间
//        if (servicePlan.getGetCarInfo()!=null&&!servicePlan.getGetCarInfo().equals("--")&&(servicePlan.getPickCarName()==null||servicePlan.getPickCarDate()==null)){
//            String[] split = servicePlan.getGetCarInfo().split(" - ");
//            //是否包含中文
//            Pattern pattern = Pattern.compile("[\u4e00-\u9fa5]");
//            for (String s : split) {
//                Matcher chineseMatcher = pattern.matcher(s);
//                if (chineseMatcher.find()){
//                    servicePlan.setPickCarName(s);
//                }else {
//                    Date parse = new Date();
//                    try {
//                        parse = DateUtil.parse(s, DateUtil.SHOW_DATE_FORMAT);
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
//                    servicePlan.setPickCarDate(parse);
//                }
//            }
//        }
        //回写车型/厂牌/配置车型等信息
        if (servicePlan.getCarModel()!=null&&servicePlan.getCarConfiguration()!=null&&servicePlan.getCarLabel()!=null)return;
        FnCustomerExpand fnCustomerExpand = servicePlan.getFnCustomerExpand();
        if (fnCustomerExpand==null)return;
        CarConfiguration carConfiguration = SpringManager.getBean(CarConfigurationRepository.class).findOne(fnCustomerExpand.getJekunModelCode());
        if (carConfiguration==null) return;
        CarModel carModel = carConfiguration.getCarModel();
        CarLabel carLabel = carConfiguration.getCarLabel();
        servicePlan.setCarModel(carModel);
        servicePlan.setCarLabel(carLabel);
        servicePlan.setCarConfiguration(carConfiguration);
    }

    /**
     * 确认服务方案完成后保存
     * @param servicePlan
     */
    private ServicePlan confirmSave(ServicePlan servicePlan){
        servicePlan = servicePlanRepository.saveAndFlush(servicePlan);
        return servicePlan;
    }

    /***
     * 限制商品重复
     */
    private void checkItemUnique(ServicePlan servicePlan) {
        if("appOrder".equals(servicePlan.getSourceBusinessType())) return;
        List<Map.Entry<String, List<ServicePlanItem>>> entries = servicePlan.getServicePlanItems().stream().collect(Collectors.groupingBy(
                servicePlanItem ->servicePlanItem.getProduct().getId()
        )).entrySet().stream().filter(stringListEntry -> stringListEntry.getValue().size() > 1).collect(Collectors.toList());

        if(entries.size() > 0) {
            Product repeatProduct = entries.get(0).getValue().get(0).getProduct();
            throw new RuntimeException("录入了重复的商品，商品：[" + repeatProduct.getId() + "]" + repeatProduct.getName());
        }
    }


    /**
     * 转价格审核
     * 计划前端处理
     * 1.判断是否有同意服务的商品
     * 2.判断是否有低于岗位限价的商品
     * 3.是否有价格为零的商品
     * @param simpleRequest
     */
    public ServicePlan toPriceAudit(SimpleRequest simpleRequest){
        ServicePlan servicePlan = simpleRequest.getO(ServicePlan.class);

        List list = servicePlan.getServicePlanItems().stream().filter(ServicePlanItem::isServiceState).collect(Collectors.toList());
        if(list.size() == 0) throw new RuntimeException("无同意服务商品");

        //判断是否需要转价格审批
        JSONObject needPriceAuditJson = needPriceAudit(servicePlan, simpleRequest);

        //判断是否需要发起价格审批流程（非价格审批退回，质检，方案确认（用于异业））
        if (LogicalUtil.notIn(servicePlan.getState(), "backPriceAudit", "confirm", "qualityTest")
                && !needPriceAuditJson.getBoolean("needPriceAudit")) {
            throw new RuntimeException("没有低于岗位限价的商品，无需转价格审核");
        }
        if(servicePlan.getConfirmDate() == null){ //方案确认前
            servicePlan.setState("toPriceAudit");
            setInformationDetail(simpleRequest,servicePlan);
        }

        // 判断是否需要转技术审核
        if(isToTechnical(servicePlan) && servicePlan.getTechnicalAuditDate() == null){
            throw new RuntimeException("存在需转技术审核的商品, 请先转技术审核！");
        }

        // 写入限价级别以及是否需要价格审批标记
        servicePlan.setPriceLimitLevel(needPriceAuditJson.getObject("limitLevel", Enumeration.class));

        servicePlan = save(servicePlan);
        auditNodeService.createPriceApprovalReport(servicePlan,simpleRequest);

        return findCarServiceLevel(servicePlan);
    }

    /**
     * 价格审核
     * 计划前端处理
     * 1.只查询有勾选同意标记的商品
     * 2.判断是哪个级别的人审核，是否不符合价格级别（不能为零）
     * 3.区分哪些是需要处理的价格审核商品
     * @param simpleRequest
     */
    public ServicePlan priceAudit(SimpleRequest simpleRequest){

        // 用于判断当前的数据状态是否为价格审批退回的状态，如果是，直接返回，用于价格审批终止节点来源于价格审批退回
        ServicePlan oldServicePlan = servicePlanRepository.findOne((String) simpleRequest.get("id"));
        if( oldServicePlan.getState().equals("backPriceAudit") ) return oldServicePlan;

        ServicePlan servicePlan = simpleRequest.getO(ServicePlan.class);

        // 判断当前审核是否合理,不允许低于当前节点的限价级别审批
        checkPriceAuditReasonable(servicePlan);
        if(servicePlan.getConfirmDate() == null){
            servicePlan.setState("priceAudit");
            setInformationDetail(simpleRequest,servicePlan);
        }
        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            servicePlanItem.setPriceApprovalAmt(servicePlanItem.getPftPriceUnit());
        });
        auditNodeService.updatePriceApproval(servicePlan,simpleRequest.get("wf_comments"),simpleRequest.get("wf_variable_wf_state"),simpleRequest);

        return save(servicePlan);
    }

    /**
     * 价格退回
     * @param simpleRequest
     * @return
     */
    public ServicePlan backPriceAudit(SimpleRequest simpleRequest){
        ServicePlan servicePlan = simpleRequest.getO(ServicePlan.class);
        if(servicePlan.getConfirmDate() == null){
            servicePlan.setState("backPriceAudit");
            setInformationDetail(simpleRequest,servicePlan);
        }
        auditNodeService.updatePriceApproval(servicePlan,simpleRequest.get("wf_comments"),simpleRequest.get("wf_variable_wf_state"),simpleRequest);
        return save(servicePlan);
    }

    /***
     * 判断当前审核是否合理(不允许超过当前节点可审批权限)
     * 1. 销售总监 副总裁 总裁统一不做任何限制
     * 2. 限制店长
     * 3. 店助节点不存在，无需检查
     */
    private void checkPriceAuditReasonable(ServicePlan servicePlan) {
        // 获取当前节点的限制级别
        String limitLevel = servicePlan.getPriceLimitLevel().getCode();
        //查询当前价格审核中的商品
        List<String> ids = auditNodeService.findCurrentApproval(servicePlan).stream()
                .filter(priceApprovalReport -> Integer.valueOf(limitLevel)<=Integer.valueOf(priceApprovalReport.getLimitLevel()))
                .map(PriceApprovalReport::getPlanItemId).collect(Collectors.toList());
        List<ServicePlanItem> filterArray;
        switch (limitLevel) {
            case "4": // 店长
                filterArray = servicePlan.getServicePlanItems().stream()
                        .filter(servicePlanItem -> servicePlanItem.isServiceState())
                        .filter(servicePlanItem -> ids.contains(servicePlanItem.getId()))
                        .filter(servicePlanItem -> (servicePlanItem.getPriceApprovalAmt()>servicePlanItem.getShopOwnerPriceLimit()?servicePlanItem.getShopOwnerPriceLimit():servicePlanItem.getPriceApprovalAmt()) > servicePlanItem.getPftPriceUnit())
                        .collect(Collectors.toList());
                break;
            default:
                filterArray = new ArrayList();
                break;
        }

        if (filterArray.size() > 0) {
            throw new RuntimeException("存在价格低于当前限价级别审批的商品：" + filterArray.stream()
                    .reduce("",(a, b) -> a + ";" + b.getProduct().getName(),String::concat)
            );
        }

        // 限制价格大于0
        List<ServicePlanItem> validPriceList =  servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem -> servicePlanItem.isServiceState())
                .filter(servicePlanItem -> servicePlanItem.getPftPriceUnit() <= 0)
                .collect(Collectors.toList());
        if (validPriceList.size() > 0) {
            throw new RuntimeException("存在价格小于等于零的商品：" + validPriceList.stream()
                    .reduce("",(a, b) -> a + ";" + b.getProduct().getName(),String::concat)
            );
        }
    }



    /**
     * 转技术审核
     *
     * @param simpleRequest
     * @return
     */
    public ServicePlan toTechAudit(SimpleRequest simpleRequest){
        ServicePlan servicePlan = simpleRequest.getO(ServicePlan.class);
        //判断是否为国产车
        checkCarInformation(servicePlan.getFnCustomerExpand());
        if(!isToTechnical(servicePlan))
            throw new RuntimeException("没有需转技术审核项目");

        servicePlan.setState("toTechAudit");
        setInformationDetail(simpleRequest,servicePlan);
        return findCarServiceLevel(save(servicePlan));
    }


    /**
     * 技术审核
     * @param simpleRequest
     * @return
     */
    public ServicePlan TechAudit(SimpleRequest simpleRequest) {
        ServicePlan servicePlan = simpleRequest.getO(ServicePlan.class);
        servicePlan.setState("techAudit");
        setInformationDetail(simpleRequest,servicePlan);
        servicePlan = save(servicePlan);
        servicePlan = MapUtil.getO(MapUtil.mapped(servicePlan),ServicePlan.class);
//        Map operateMap = toInquiry_detail(simpleRequest,servicePlan,true);2021-07-12 取消技术审核自动转询价
//        String operate = (String)operateMap.get("operate");
        String operate = "notInquiry";
        switch (operate){
            case  "toInquiry":
//                servicePlan.setState("toInquiry");
                servicePlan.setState("techAudit");
                servicePlan.setTechnicalAuditComments(servicePlan.getTechnicalAuditComments() + ";技术审核自动询价" );
                servicePlan = this.invoke("fn.service.toInquiryDB",MapUtil.mapped(servicePlan)); //为了日志
                break;

            case "notInquiry":
                servicePlan.setState("techAudit");
                break;
            default:
                throw new RuntimeException("发生内部错误");
        }
        setInquiryDetail(simpleRequest,servicePlan,operate);
        servicePlan = save(servicePlan);
//        if("toInquiry".equals(operate))
//        createCommodityInquiry(servicePlan,(Map)operateMap.get("inquiryMap"),getPerson(simpleRequest)); //创建商品询价单
        return servicePlan;
    }


    /**
     * 技术退回
     * @param simpleRequest
     * @return
     */
    public ServicePlan backTechAudit(SimpleRequest simpleRequest){
        ServicePlan servicePlan = simpleRequest.getO(ServicePlan.class);
        servicePlan.setState("backTechAudit");
        setInformationDetail(simpleRequest,servicePlan);
        return save(servicePlan);
    }

    /**
     * 转询价
     * @param simpleRequest
     * @return
     */
    public ServicePlan toInquiry(SimpleRequest simpleRequest){
        ServicePlan servicePlan = simpleRequest.getO(ServicePlan.class);

        //判断是否需要图片的商品
        checkProductPic(servicePlan);
        //判断是否为国产车
        Map inquireOtherInfo = checkCarInformation(servicePlan.getFnCustomerExpand());
        try {
            this.invoke("fn.deliveryOrder.acrossSystemCreateVipDetail", MapUtil.mapper(
                    "customerExpandId", servicePlan.getFnCustomerExpand().getId(),
                    "deliveryCompanyId", servicePlan.getBelongDept().getCompany().getId(),
                    "receiptCompanyId", servicePlan.getServiceDept().getCompany().getId()
            ));
        } catch (Exception e) {
            throw new RuntimeException("会员车辆信息有误，请联系客服中心对接人,错误信息为:"+e.getMessage());
        }
        if(isToTechnical(servicePlan) && servicePlan.getTechnicalAuditDate() == null)
            throw new RuntimeException("请先转技术审核！");
        Map operateMap = toInquiry_detail(servicePlan,false);

        servicePlan = save(servicePlan);
//        getBean(FnEnquiryService.class).turnEnquiry(simpleRequest);//供应商平台询价
//        createCommodityInquiry(servicePlan,(Map)operateMap.get("inquiryMap"),getPerson(simpleRequest), inquireOtherInfo); //创建商品询价单
        return getCurrentTimeData(servicePlan);
    }

    /**
     * 产生日志用
     * @param simpleRequest
     */
    public ServicePlan toInquiryDB(SimpleRequest simpleRequest){
        ServicePlan servicePlan = simpleRequest.getO(ServicePlan.class);
        return servicePlanRepository.saveAndFlush(servicePlan);
    }

    /**
     * 检查商品是否需要图片
     * @param servicePlan
     */
    public void checkProductPic(ServicePlan servicePlan){
        List<ServicePlanItem> needPicture = servicePlan.getServicePlanItems().stream().filter(servicePlanItem -> servicePlanItem.getProduct().getInquiryValid()).collect(Collectors.toList());
        if (needPicture.size()>0){
            StringBuffer sf = new StringBuffer();
            sf.append("转询价失败,以下配件需要上传图片");
            List<ServicePlanItem> noFile = needPicture.stream().filter(servicePlanItem -> {
                JSONArray mapAddress = JSONObject.parseArray(servicePlanItem.getMapAddress());
                if (mapAddress.size()==0){
                    sf.append(", ["+servicePlanItem.getProduct().getId()+"]"+servicePlanItem.getProduct().getName());
                }
                return mapAddress.size()==0;
            }).collect(Collectors.toList());
            if (noFile.size()>0)throw new RuntimeException(sf.toString());
        }
    }

    /**
     * 转询价--main
     * operate  : toInquiry finishInquiry notInquiry
     * @param servicePlan
     * @param auditFlag
     * @return
     */
    public Map toInquiry_detail(ServicePlan servicePlan,boolean auditFlag){

        //需要排除不服务的商品去查询是否询价2021-07-09 更改为只要勾选了就询价
        Map service = MapUtil.mapped(servicePlan);
        ServicePlan plan = MapUtil.getO(service, ServicePlan.class);
        Map resultMap = new HashMap();
        Map<String,List<ServicePlanItem>> map = this.getInquiryGoods(servicePlan); //需要询价商品
        resultMap.put("operate","toInquiry");
        resultMap.put("inquiryMap",map);
        return resultMap;
    }

    /**
     * 根据商品质检匹配，处理询价报错，但是不直接提示的商品
     * @param servicePlan
     * @param jsonArray
     */
    private void dealInquiryErrorGoods(ServicePlan servicePlan, JSONArray jsonArray) {
        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            jsonArray.forEach(tempJson ->{
                JSONObject json = (JSONObject)tempJson;
                if(json.getString("SPID").equals(servicePlanItem.getProduct().getId())){
                    servicePlanItem.setRemarks(servicePlanItem.getRemarks() + "<系统备注>" + json.getString("errorMessage"));
                }
            });
        });
    }


    /**
     * 完成询价
     * @return
     */
    @OutboxSubscriber(id="servicePlan.server.finishInquiry", name="询价完成调用方案")
    public ServicePlan finishInquiry(OutboxPayloadWrapper wrapper){
        JSONObject tempJson = JSON.parseObject(wrapper.getPayload());
        ServicePlan servicePlan = servicePlanRepository.findOne(tempJson.getString("sourceBusinessKey"));
//        dealInquiryGoods(servicePlan,tempJson);
        return save(servicePlan);
    }


    public ServicePlan finishConfirm(OutboxPayloadWrapper wrapper){
        JSONObject tempJson = JSON.parseObject(wrapper.getPayload());
        ServicePlan servicePlan = servicePlanRepository.findOne(tempJson.getString("sourceBusinessKey"));
        dealConfirmGoods(servicePlan,tempJson);
        return confirmSave(servicePlan);
    }

    /**
     * 取消终止报价
     * @return
     */
    @OutboxSubscriber(id="fn.servicePlan.backInquiry", name="取消报价方案退回")
    public ServicePlan backInquiry(OutboxPayloadWrapper outboxPayloadWrapper){
        JSONObject json = JSONObject.parseObject(outboxPayloadWrapper.getPayload());
        ServicePlan servicePlan = servicePlanRepository.findOne(json.getString("id"));
        if(servicePlan == null) throw new RuntimeException("来源单据有误，无法退回询价，来源方案缺失");

//        if(!Objects.equals("toInquiry",servicePlan.getState())) throw new RuntimeException("不处于转询价状态");

//        servicePlan.setState("backInquiry");
        servicePlan.setToInquiryDate(new Date());
        servicePlan.setToInquiryUid(MapUtil.getO(json.get("roleId"),PartyRole.class));
        return save(servicePlan);
    }


    private void dealConfirmGoods(ServicePlan servicePlan, JSONObject tempJson) {
        JSONArray inquiryGoodsArray = tempJson.getJSONArray("PUR_SPXJDMX");

        //3.添加价格信息
        inquiryGoodsArray.stream().forEach((item) -> {  //只要商品一致，那么就退换询价信息
            JSONObject quiryJson = (JSONObject) item;
            servicePlan.getServicePlanItems().stream().forEach(servicePlanItem -> {
                if (servicePlanItem.getProduct().getOrginID() == null)
                    throw new RuntimeException("该商品没有外部编码，商品编码" + servicePlanItem.getProduct().getId());
                if (quiryJson.getString("SPID").equals(servicePlanItem.getProduct().getOrginID())) {
                    quiryJson.put("COMPANYID",servicePlan.getCompany().getId());
                    quiryJson.put("OPERATION",servicePlan.getCompany().getParty().getCorporate().getOperation().getDescription());
                    addConfirmParas(servicePlanItem, quiryJson);
                }
            });
        });
    }


    /**
     * 提交
     * @param simpleRequest
     * @return
     */
    public ServicePlan submission(SimpleRequest simpleRequest){
        ServicePlan servicePlan = simpleRequest.getO2(ServicePlan.class);

        //判断能否提交
        checkSubmissionCondition(servicePlan);

        //增加判断是否存在分类为M01010102.M0103，有价格无库存商品且未询价，有，则提交失败，并提示‘******有价格无库存，请转询价’
        checkPriceStock(servicePlan);
        //判断是否询价过期
        checkInquiryPool(servicePlan);
        //判断是否价格/技术审批
        checkAudit(simpleRequest, servicePlan);
        //提交流程
        submitProcess(simpleRequest, servicePlan);

        this.submitSynGYSXJD(servicePlan.getId());
        return save(servicePlan);
    }

    private void createSourceFromPlan(ServicePlan servicePlan) {
        if(servicePlan.checkInnerServicePlan()){
            ServicePlan belongDeptPlan = createBelongDeptPlan(servicePlan);
            //服务门店作为子方案，绑定父方案
            servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
                belongDeptPlan.getServicePlanItems().forEach(servicePlanItem1 -> {
                    if(servicePlanItem1.getProduct().getId().equals(servicePlanItem.getProduct().getId())){
                        servicePlanItem.setParentServicePlanItem(servicePlanItem1);
                        servicePlanItem.setAssistType(businessAttributeValueRepository.findOne("ServicePlanItem.assistType.normal"));
                        servicePlanItem1.setParentServicePlanItem(null);
                        servicePlanItem1.setInnerServicePlanItem(servicePlanItem.getId());
                    }
                });
            });
            maintenanceOrderService.setPlanSource(servicePlan,belongDeptPlan);
            servicePlan.setLockServicePlan(true);
        }
    }

    private ServicePlan createBelongDeptPlan(ServicePlan servicePlan) {
        ServicePlan newServicePlan = createServicePlanByInnerServicePlan(servicePlan);
        initPlan(newServicePlan);
        getPlanDept(newServicePlan,newServicePlan.getBelongDept().getBranch().getId());
        updateOnly(newServicePlan);
        return newServicePlan;
    }

    private void changeSubmissionItem(ServicePlan servicePlan) {
        String COMPANY_ID = servicePlan.getCompany().getId();
        String OPERATION = servicePlan.getCompany().getParty().getCorporate().getOperation().getDescription();

        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            //设置不同意的隐藏
            if (!servicePlanItem.isServiceState()) servicePlanItem.changerInquirySelectFlag(0);
            //设置一个预估提成（包括基地做的方案，门店做的方案）
//            异步处理
            if (!servicePlanItem.getServicePlan().checkBigBusiness()) {
                servicePlanItem.setEstimatedCommission((Double) (SpringManager.getBean(TCService.class).obtainEstimatedCommission(
                        servicePlanItem.getProduct().getId(),
                        servicePlanItem.getProduct().getClassify().getId(),
                        servicePlanItem.getServeType().getId(),
                        servicePlanItem.getProduct().getBrand().getId(),
                        servicePlanItem.getReferTax(),
                        servicePlanItem.getPftPriceUnit(),
                        servicePlanItem.getFloorPrice(),
                        servicePlanItem.getPriceUnit(),
                        COMPANY_ID, OPERATION
                )));
            }
        });
        //推送预估提成
        if (servicePlan.checkBigBusiness())
            pushOutboxEstimatedCommission(servicePlan);
    }

    /**
     * 推送预估提成
     * @param order
     */
    private void pushOutboxEstimatedCommission(ServicePlan order) {
        JSONObject json = new JSONObject();
        json.put("id", order.getId());
        json.put("note", "计算预估提成中");

        // 推送消息
        OutboxPayloadWrapper wrapper = new OutboxPayloadWrapper();
        wrapper.setSubscriber("fn.server.calculateEstimatedCommission");
        wrapper.setAggregateId(order.getId()+":EC");// 加在后面方便模糊查找
        wrapper.setPayload(json.toJSONString());
        SpringManager.getBean(OutboxEventService.class).sendSaveEvent(wrapper);
    }
    private void pushOutboxEstimatedCommissionTest(SimpleRequest request){
        JSONArray jsonArray = servicePlanDao.queryServerEstimatedCommission(request.getJO());
        jsonArray.forEach(json ->{
            JSONObject jsonObject = (JSONObject) json;
            JSONObject json2 = new JSONObject();
            json2.put("id", jsonObject.getString("ID"));
            json2.put("note", "计算预估提成中");
            // 推送消息
            OutboxPayloadWrapper wrapper = new OutboxPayloadWrapper();
            wrapper.setSubscriber("fn.server.calculateEstimatedCommission");
            wrapper.setAggregateId(jsonObject.getString("ID")+":EC");// 加在后面方便模糊查找
            wrapper.setPayload(json2.toJSONString());
            SpringManager.getBean(OutboxEventService.class).sendSaveEvent(wrapper);
        });
    }

    @OutboxSubscriber(id="fn.server.calculateEstimatedCommission", name="计算预估提成中")
    public void calculateEstimatedCommission(OutboxPayloadWrapper wrapper){
        JSONObject param = JSONObject.parseObject(wrapper.getPayload());
        String id = param.getString("id");
        ServicePlan servicePlan = servicePlanRepository.findOne(id);
        if ("termination".equals(servicePlan.getState()))return;
        if (servicePlan.getSubmissionDate()==null)
            throw new RuntimeException("方案未提交");
        String COMPANY_ID = servicePlan.getCompany().getId();
        String OPERATION = servicePlan.getCompany().getParty().getCorporate().getOperation().getDescription();
        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            servicePlanItem.setEstimatedCommission((Double)(SpringManager.getBean(TCService.class).obtainEstimatedCommission(
                    servicePlanItem.getProduct().getId(),
                    servicePlanItem.getProduct().getClassify().getId(),
                    servicePlanItem.getServeType().getId(),
                    servicePlanItem.getProduct().getBrand().getId(),
                    servicePlanItem.getReferTax(),
                    servicePlanItem.getPftPriceUnit(),
                    servicePlanItem.getFloorPrice(),
                    servicePlanItem.getPriceUnit(),
                    COMPANY_ID,OPERATION
            )));
            servicePlanItem.setEstimatedCommissionFlag("1");
        });
        servicePlan.setLastUpdatedStamp(new Date());
        servicePlanRepository.saveAndFlush(servicePlan);
    }

    private void checkAudit(SimpleRequest simpleRequest, ServicePlan servicePlan) {
        if(servicePlan.getOrderOrigin() == null || !"APP".equals(servicePlan.getOrderOrigin())){
            // 判断是否需要转技术审核
            if(isToTechnical(servicePlan) && servicePlan.getTechnicalAuditDate() == null){
                throw new RuntimeException("存在需转技术审核的商品, 请先转技术审核！");
            }

            // 判断是否需要转价格审批
            JSONObject needPriceAuditJson = needPriceAudit(servicePlan, simpleRequest);
            if( needPriceAuditJson.getBoolean("needPriceAudit") ) {
                throw new RuntimeException("存在需转价格审批的商品, 请先转价格审批！");
            }
        }
    }

    private void checkPriceStock(ServicePlan servicePlan) {
        List classifyList = servicePlan.getServicePlanItems().stream().filter(servicePlanItem -> {
            Classify classify = servicePlanItem.getProduct().getClassify();
            List<ProductNegativeSelling>  productNegativeSellingList = productNegativeSellingRepository.findAll(JpaDsl.toCriteriaByEq("product.id", servicePlanItem.getProduct().getId(), "valid", true));
            return  productNegativeSellingList.isEmpty() && (!servicePlanItem.isProductRule()) && servicePlanItem.isServiceState() && servicePlanItem.getOldInquiryNumber() == null && servicePlanItem.getPriceUnit() != 0  && (classify.getId().startsWith("M01010102") || classify.getId().startsWith("M0103"));
        }).filter(servicePlanItem -> LogicalUtil.notIn(servicePlanItem.getPriceForward(),"1","2","4","5")).map(servicePlanItem -> {return MapUtil.mapper("productId",servicePlanItem.getProduct().getId());}).collect(Collectors.toList());

        if( classifyList.size() !=0 && servicePlan.getCheckStock() ){
            JSONObject json = new JSONObject();
            json.put("NEW_DEPT_ID", servicePlan.getBelongDept().getId());
            json.put("OLD_DEPT_ID", servicePlan.getBelongDept().getOrigin());
            json.put("productList", classifyList);
            JSONArray array = servicePlanDao.queryProductStoreForList(json);

            JSONArray resultList = array.stream().filter(tempJson ->{
                JSONObject item = (JSONObject)tempJson;
                return item.getDoubleValue("GENERAL_STOCK") + item.getDoubleValue("SUB_STOCK") + item.getDoubleValue("STOCK_AMOUNT") <= 0;
            }).collect(Collectors.toCollection(JSONArray :: new));

            if(resultList.size() != 0)  throw new RuntimeException(resultList.getJSONObject(0).getString("NAME") + ",有价格无库存，请转询价");
        }
    }

    private void checkSubmissionCondition(ServicePlan servicePlan) {
        if(servicePlan.getConfirmDate()!=null) throw new RuntimeException("该方案已确认请勿重复提交");
        // 做服务方案，提交时，如果检查接车单为‘外部定损’，则判断必须要上传‘定损清单’；
        List lossList = servicePlan.getPickUpTypeS().stream().filter(PickUpTypeS::obtainOutLoss).collect(Collectors.toList());
        if(lossList.size() != 0 && servicePlan.getLossList() == null) throw new RuntimeException("该车为外部定损车，请上传定损清单") ;
        //检查是否有有效商品
        List<ServicePlanItem> list= servicePlan.getServicePlanItems().stream().filter(ServicePlanItem::isServiceState).collect(Collectors.toList());
        if(list.size() == 0) throw new RuntimeException("无有效服务商品");
    }


    /**
     * 转内协明细填写
     * @param basePlan 基地方案
     */
    public void toInnerItemWrite(ServicePlan basePlan){
        for (ServicePlanItem servicePlanItem : basePlan.getServicePlanItems()) {
            ServicePlanItem parentServicePlanItem = servicePlanItem.getParentServicePlanItem();
            if (parentServicePlanItem!=null){
                parentServicePlanItem.setInnerServicePlanItem(servicePlanItem.getId());
                servicePlanItemRepository.saveAndFlush(parentServicePlanItem);
            }
        }
    }


    private String getPriceLimitLevel(SimpleRequest simpleRequest){
        try {
            String code = this.invoke("aut.post.findPriLimitLevelCode",MapUtil.mapper("postId",getSession(simpleRequest).getPostId()));
            if(code == null || "".equals(code.trim())) throw new RuntimeException("请联系行政定义当前岗位的限价级别");
            return code;
        }catch (Exception e){
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 退回
     * @param simpleRequest
     * @return
     */
    public ServicePlan goBack(SimpleRequest simpleRequest){
        String id = simpleRequest.get("id");
        ServicePlan servicePlan = servicePlanRepository.findOne(id);
        if (servicePlan.getConfirmDate() != null) throw new RuntimeException("方案已确认,无法退回");
        servicePlan.setState("goBack");
        setInformationDetail(simpleRequest,servicePlan);
        servicePlan.setSubmissionDate(null);
        servicePlan.setSubmissionUid(null);
        servicePlan.setToTechnicalAuditDate(null);
        servicePlan.setToTechnicalAuditUid(null);
        servicePlan.setTechnicalAuditDate(null);
        servicePlan.setTechnicalAuditUid(null);
        servicePlan.setToPriceAuditDate(null);
        servicePlan.setToPriceAuditUid(null);
        servicePlan.setPriceAuditUid(null);
        servicePlan.setPriceAuditDate(null);
        servicePlan.setState("create");
        servicePlan.setLockServicePlan(false);
        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            servicePlanItem.changerInquirySelectFlag(1);
            servicePlanItem.setEstimatedCommissionFlag("0");
        });
        checkSourceOrder(servicePlan);
//        servicePlan = save(servicePlan);
        servicePlan = updateOnly(servicePlan);
        //判断是否整单内协，来源门店方案进行终止
        if(servicePlan.allInnerOtherSide()){
            endOriginServicePlan(servicePlan);
            servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
                servicePlanItem.setParentServicePlanItem(null);
            });
            updateOnly(servicePlan);
        }

        return servicePlan;
    }
    private void checkSourceOrder (ServicePlan servicePlan) {
        if (Objects.equals("LossQuotation", servicePlan.getSourceBusinessType())) {
            LossQuotation lossQuotation = lossQuotationRepository.findOne(servicePlan.getSourceFrom());
            if (Objects.isNull(lossQuotation)) {
                throw new RuntimeException("未找到对应定损单数据!!!");
            }
            if (!Objects.equals("businessAudit",lossQuotation.getState())) {
                throw new RuntimeException("该服务方案的来源定损单还未完成,不能退回!!!");
            }
            if (!Objects.equals("B",lossQuotation.getOrderType().getCode())) {
                throw new RuntimeException("该服务方案的来源定损单不是委托定损,不能退回!!!");
            }
        }
    }
    /**
     *整单内协，基地退回，门店方案终止
     * @param servicePlan
     */
    private void endOriginServicePlan(ServicePlan servicePlan) {
        ServicePlan originServicePlan = findOriginServicePlanByCurrentServicePlan(servicePlan);
        if(originServicePlan.getConfirmDate() != null) throw new RuntimeException("来源门店已经进行方案确认，不可退回");
        if("toPriceAudit".equals(originServicePlan.getState()) || "backPriceAudit".equals(originServicePlan.getState())) throw new RuntimeException("来源门店处于价格审批中，不可退回");
        originServicePlan.setTerminationDate(new Date());
        originServicePlan.setTerminationUid(servicePlan.getGoBackUid());
        originServicePlan.setState("termination");
        originServicePlan.getServicePlanItems().stream().forEach(servicePlanItem -> {
            servicePlanItem.setTerminationDate(new Date());
            servicePlanItem.setTerminationUid(servicePlan.getGoBackUid());
            servicePlanItem.setTerminationFlag(true);
        });
        updateOnly(originServicePlan);
        this.submitSynGYSXJD(servicePlan.getId());
    }

    /**
     * 确认
     * @param simpleRequest
     * @return
     */
    public ServicePlan confirm(SimpleRequest simpleRequest){
//        int chooseWarehouse = 0; //代表选择仓库
        String id = simpleRequest.get("id");
        ServicePlan servicePlan = servicePlanRepository.findOne(id);
        if (simpleRequest.get("chooseWarehouse")!=null)servicePlan.setChooseWarehouse(simpleRequest.get("chooseWarehouse"));
        if (simpleRequest.get("promptConfirm")!=null)servicePlan.setPromptConfirm(simpleRequest.get("promptConfirm"));
        //判断询价池
        checkInquiryPool(servicePlan);

        try {
            servicePlan = confirmProcess(simpleRequest, servicePlan);
        } catch (Exception e) {
            e.printStackTrace();
            sendServeErrorToMongoDB(servicePlan.getId(),e,"方案确认报错");
            throw e;
        }

        //通知app调用接口
        if (!"appCrossIC".equals(servicePlan.getSourceBusinessType())){//app异业生成方案时不通知 异业操作时会通知一次
            confirmToApp(servicePlan);
        }
        return getCurrentTimeData(servicePlan);
    }

    private ServicePlan confirmProcess(SimpleRequest simpleRequest, ServicePlan servicePlan) {
        if(servicePlan.getConfirmDate() != null) throw new RuntimeException("已完成确认，请刷新界面");
        servicePlan.getServicePlanItems().forEach(servicePlanItem->{
            servicePlanItem.setPftPriceUnitCross(servicePlanItem.getPftPriceUnit());
            if(servicePlanItem.isServiceState() && servicePlanItem.getMainSaler() == null)
                throw new RuntimeException("请分配销售员" );
        });

        servicePlan.setState("confirm");
        setInformationDetail(simpleRequest,servicePlan);
        servicePlan.setOperator1(getPerson(simpleRequest) != null ? getPerson(simpleRequest) : servicePlan.getOperator1());
        String confirmRouter = setRouter(servicePlan);
        List<MaintenanceOrder> maintenanceOrdersAutoOut = new ArrayList<>();
//        writeDB(CONST_REQUIRE_COLLECTION_NAME,servicePlan.getId(), MapUtil.mapper("confirmRouter",confirmRouter),"方案确认走的路径");
        switch(confirmRouter){
            case "common":
                requireGoods(servicePlan,simpleRequest); //要货
                dealFrozenQty(servicePlan,true,"服务方案确认");

                List<MaintenanceOrder> maintenanceOrders = servicePlanCreateMaintenance(servicePlan);

                maintenanceOrdersAutoOut = maintenanceOrders;
                break;
            case "innerSale": //销售门店端进行确认
                List<MaintenanceOrder> maintenanceOrders1 = servicePlanCreateMaintenanceSale(servicePlan);
                //（对原方案进行数据更改）
                unlockInnerServicePlan(servicePlan);
                break;
            case "innerService"://服务门店端进行确认
                if(servicePlan.isLockServicePlan())
                    throw new RuntimeException("内协方案：请联系对应门店先进行方案确认，门店编码" + servicePlan.getSaleDept().getName());
                requireGoods(servicePlan,simpleRequest); //要货
                dealFrozenQty(servicePlan,true,"服务方案确认");
                List<MaintenanceOrder> maintenanceOrders2 = servicePlanCreateMaintenanceService(servicePlan);

                maintenanceOrdersAutoOut = maintenanceOrders2;
                break;

            default:
                throw new RuntimeException("程序错误");
        }
        // 明细状态
        confirmItemState(servicePlan);
        // 回写明细要货数量
//        itemQtyRequire(servicePlan);
        servicePlan = save(servicePlan);

        if(maintenanceOrdersAutoOut != null && maintenanceOrdersAutoOut.size() != 0){
            //根据产生工单判断是否自动转外协
            commonOrder2OutOrder(maintenanceOrdersAutoOut,servicePlan.getServicePlanItems());
        }
        return servicePlan;
    }

    /**
     * 判断询价池
     * @param servicePlan
     */
    public void checkInquiryPool(ServicePlan servicePlan){

        List<ServicePlanItem> servicePlanItems = servicePlan.getServicePlanItems();

        if (servicePlanItems.stream().noneMatch(servicePlanItem -> servicePlanItem.getUniqueValue() != null))return;

        Map inquiryPool = null;

        //过滤需要询价的商品
        List<ServicePlanItem> needCheckItems = servicePlanItems
                .stream()
                .filter(servicePlanItem ->
                    //过滤出需要询价的商品
                    servicePlanItem.isProductRule() || servicePlanItem.getProduct().getProductGroup().getId().equals("10") || servicePlanItem.getUniqueValue() != null ||servicePlanItem.getPriceForward()!=null
                ).filter(servicePlanItem -> {
                    //过滤出库存不足的商品
                    JSONObject json = new JSONObject();
                    json.put("deptId", servicePlan.getServiceDept().getId());
                    json.put("productId", servicePlanItem.getProduct().getId());
                    double planKys = servicePlanDao.queryLocalStore(json);
                    return planKys < (servicePlanItem.getSaleQty() - servicePlanItem.getQtyEnd());
                }).collect(Collectors.toList());


        for (ServicePlanItem servicePlanItem : needCheckItems) {
            //判断新平台询价
            if (checkNewPlatform(servicePlanItem))
                continue;
            //判断外采询价
            if (checkExternalInquiry(servicePlanItem))
                continue;
            //老系统询价
            if (servicePlanItem.getUniqueValue()!=null){
                if (inquiryPool==null){
                    inquiryPool = this.invoke("commodityInquiry.order.getInquiryPool",new JSONObject(MapUtil.mapped(servicePlan,"servicePlanItems")) );
                }
                checkOldSystemInquiry((List) inquiryPool.get("item"), servicePlanItem);

            }
        }
    }

    private boolean checkExternalInquiry(ServicePlanItem servicePlanItem) {
        if (!servicePlanItem.checkExternalInquiry()) return false;
        boolean invoke = invoke("scm.externalInquiryService.sourceConfirmPriceValid", mapper("id", servicePlanItem.getOldInquiryNumber(), "unique", servicePlanItem.getUniqueValue()));
        if (!invoke)throw new RuntimeException("存在询价过期商品:"+servicePlanItem.getProduct().getName());
        return true;
    }

    private boolean checkNewPlatform(ServicePlanItem servicePlanItem) {
        if (Objects.nonNull(servicePlanItem.getPriceForward()) && "1-4".contains(servicePlanItem.getPriceForward()))//价格前置商品
            return true;
        if("2".equals(servicePlanItem.getPriceForward())){ //新平台询价
            JSONObject result =  JSON.parseObject(invoke("sp.enquiryService.findByID", MapUtil.mapper("id",servicePlanItem.getOldInquiryNumber())));
            JSONObject body = result.getJSONObject("body");
            JSONObject  isState =  JSON.parseObject(invoke("sp.enquiryService.findQuoteResultState",MapUtil.mapper("id",servicePlanItem.getUniqueValue())));
            boolean state = isState.getBoolean("body");

            if(body!=null && new Date().getTime()<body.getDate("quoteExpireDate").getTime() && state) return true;
            throw new RuntimeException("存在询价过期商品:"+servicePlanItem.getProduct().getName());
        }
        //巴图鲁询价
        if ("5".equals(servicePlanItem.getPriceForward())){
            //获取巴图鲁询价过期时间
            JSONObject  result =  JSON.parseObject(invoke("sp.quoteResult.findOne",MapUtil.mapper("id",servicePlanItem.getQuoteResultId())));
            JSONObject body = result.getJSONObject("body");
            if(body!=null && new Date().getTime()<body.getDate("expiredTime").getTime() && body.getString("state") != "20") return true;
            throw new RuntimeException("存在询价过期商品:"+servicePlanItem.getProduct().getName());
        }
        return false;
    }

    private void checkOldSystemInquiry(List items2, ServicePlanItem servicePlanItem) {
        boolean outFlag;
        outFlag=false;
        //先判断是否在有效期内
        for ( Object item : items2) {
            JSONObject sourceProduct = new JSONObject((Map) item);
            for (Object o : sourceProduct.getJSONArray("item")) {
                JSONObject inquiryProduct = new JSONObject((Map) o);
                if (inquiryProduct.getString("WYZ").equals(servicePlanItem.getUniqueValue())){
                    outFlag=true;
                }
            }
        }
//                //不在有效期就判断是否在询价保留期 取消询价保留期概念 有可用数就不会过期
//                if (!outFlag){
//                    for ( Object item : items2) {
//                        JSONObject sourceProduct = new JSONObject((Map) item);
//                        for (Object o : sourceProduct.getJSONArray("item")) {
//                            JSONObject inquiryProduct = new JSONObject((Map) o);
//                            if (inquiryProduct.getString("WYZ").equals(servicePlanItem.getUniqueValue())){
//                                if (planKys<(servicePlanItem.getSaleQty()-servicePlanItem.getQtyEnd())){
//                                    throw new RuntimeException("询价保留期商品要货数大于库存数:"+servicePlanItem.getProduct().getName());
//                                }
//                                outFlag=true;
//                            }
//                        }
//                    }
//                }


        if (!outFlag){
            throw new RuntimeException("存在询价过期商品,请重新询价:"+servicePlanItem.getProduct().getName());
        }
    }

    /**
     * 方案确认时，两种场景（门店普通确认，整单内协服务段进行确认），会导致自动转外协（询价供应商为外协外采）
     * @param maintenanceOrders
     * @param
     * @return
     */
    public List<MaintenanceOrder> commonOrder2OutOrder(List<MaintenanceOrder> maintenanceOrders,List<ServicePlanItem> servicePlanItems){
        if(maintenanceOrders == null) return null;
        List<String> conditionList = servicePlanItems.stream()
                .filter(servicePlanItem -> servicePlanItem.isServiceState() && servicePlanItem.getOldInquiryNumber() != null)
                .map(ServicePlanItem::getOldInquiryNumber)
                .collect(Collectors.toList());

        if(conditionList.size() != 0){
            List<MaintenanceOrder> resultList= maintenanceOrderService.obtainCPFOMaintenanceOrder(maintenanceOrders);
            if(resultList == null || resultList.size() == 0) return null;
            //勾选上
            resultList.forEach(maintenanceOrder -> maintenanceOrder.setSelected(true));
            this.invoke("fn.maintenance.toOutForInvoke",MapUtil.mapper("maintenanceOrders", MapUtil.mapped(resultList))); //执行转外协操作

            List<MaintenanceOrder> outResultList = maintenanceOrderRepository.findMaintenanceOrderByIdList(resultList.stream().map(MaintenanceOrder::getId).collect(Collectors.toList()));
            //勾选上
            outResultList.forEach(maintenanceOrder -> { maintenanceOrder.setSelected(true); });
            this.invoke("fn.maintenance.dispach",MapUtil.mapper("maintenanceOrders", MapUtil.mapped(outResultList)));
            return outResultList;
        }
        return null;
    }


    /**
     * 新框架，销售门店进行确认。修改来源方案数据（数量，是否服务，解锁）
     * @param servicePlan
     */
    private void unlockInnerServicePlan(ServicePlan servicePlan) {
        String itemId = servicePlan.getServicePlanItems().stream().findFirst().get().getId();
        ServicePlan servicePlan1 ;
        try {
            servicePlan1 = servicePlanItemRepository.findAll(JpaDsl.toCriteriaByEq("parentServicePlanItem.id",itemId)).stream().findFirst().get().getServicePlan();
        }catch (Exception e){
            throw new RuntimeException("找内协方案有误，请联系开发解决");
        }

        servicePlan1.getServicePlanItems().stream().forEach(servicePlanItem1 -> {
            servicePlan.getServicePlanItems().stream().forEach(servicePlanItem -> {
                if(servicePlanItem1.isServiceState() && servicePlanItem1.getParentServicePlanItem().getId().equals(servicePlanItem.getId())){
                    servicePlanItem1.setSaleQty(servicePlanItem.getSaleQty());
                    servicePlanItem1.setServiceState(servicePlanItem.isServiceState());
                }
            });
        });
        servicePlan1.setLockServicePlan(false);
        save(servicePlan1);
    }
    /**
     * 方案确认走的路径
     * @param servicePlan
     * @return
     */
    private String setRouter(ServicePlan servicePlan) {
        String result = "common";
        String belongId = servicePlan.getBelongDept().getId();
        String saleDeptId = servicePlan.getSaleDept().getId();
        String serviceDeptId = servicePlan.getServiceDept().getId();
        String oldSource = servicePlan.getOldFrameSourceFrom();
        if(belongId.equals(saleDeptId) && saleDeptId.equals(serviceDeptId) && oldSource == null){//新框架普通做单
            result = "common";
        }else if(belongId.equals(saleDeptId) && !saleDeptId.equals(serviceDeptId) && oldSource == null ){ //新框架整单内协，销售门店进行确认
            result = "innerSale";
        }
        else if(!belongId.equals(saleDeptId) && belongId.equals(serviceDeptId) && oldSource == null){//新框架整单内协,服务门店确认
            result = "innerService";
        }else{
            throw new RuntimeException("方案确认有误");
        }
        return result;
    }

    /**
     * 根据方案生成工单（本门店做单）
     * @param servicePlan
     */
    public List<MaintenanceOrder> servicePlanCreateMaintenance(ServicePlan servicePlan) {
        boolean isPickUpCar = !isPickUpCar(servicePlan);
        Dept belongDept = servicePlan.getBelongDept();
//        Store store = SpringManager.getBean(StoreService.class).findStoreByDept(belongDept);
        List<MaintenanceOrder> maintenanceOrders = servicePlan.getServicePlanItems()
                .stream()
                .filter(servicePlanItem -> {
                    //服务并且是工时或者带安
                    return servicePlanItem.isServiceState()
                            && ("20".equals(servicePlanItem.getProduct().getProductGroup().getId()) || servicePlanItem.isProductRule());
                }).map(servicePlanItem -> maintenanceOrderService.planCreateCommonWorkOrder(servicePlan, isPickUpCar, servicePlanItem,MaintenanceOrder.WORK_ORDER_COMMON)).collect(Collectors.toList());
        if (maintenanceOrders.isEmpty()) return null;
//        List<MaintenanceOrder> maintenanceOrders = this.invoke("fn.maintenance.createMaintenanceOrders", MapUtil.mapper("maintenanceOrders", maintenanceOrders));

        //回写绑定关系（配件绑定工单）
        servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem -> servicePlanItem.getHigherLevelCode() != null)
                .forEach(servicePlanItem -> {
                    MaintenanceOrder maintenanceOrder1 = maintenanceOrders.stream()
                            .filter(maintenanceOrder -> servicePlanItem.isServiceState() &&
                                    maintenanceOrder.getServicePlanItem().getProduct().getId().equals(servicePlanItem.getHigherLevelCode()))
                            .findFirst().orElse(null);
                    if (maintenanceOrder1 != null) {
                        servicePlanItem.setRelevanceWorkOrder(maintenanceOrder1.getId());
                    }
                });
        return maintenanceOrders;

    }

    /**
     * 根据方案生成工单（内外协销售门店确认）
     * @param servicePlan
     */
    public List<MaintenanceOrder> servicePlanCreateMaintenanceSale(ServicePlan servicePlan) {
        boolean isPickUpCar = !isPickUpCar(servicePlan);
        List<MaintenanceOrder> maintenanceOrders = servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem -> servicePlanItem.isServiceState() && ("20".equals(servicePlanItem.getProduct().getProductGroup().getId()) || servicePlanItem.isProductRule()))
                .map(servicePlanItem ->
                                maintenanceOrderService.planCreateInnerWorkOrder(servicePlan, isPickUpCar, servicePlanItem,MaintenanceOrder.WORK_ORDER_COMMON)
                ).collect(Collectors.toList());
        if (maintenanceOrders.isEmpty()) return null;

//        List<MaintenanceOrder> maintenanceOrders = this.invoke("fn.maintenance.createMaintenanceOrders", MapUtil.mapper("maintenanceOrders", list));

        //回写绑定关系（配件绑定工单）
        servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem -> servicePlanItem.getHigherLevelCode() != null)
                .forEach(servicePlanItem -> {
                    MaintenanceOrder maintenanceOrder1 = maintenanceOrders.stream()
                            .filter(maintenanceOrder -> servicePlanItem.isServiceState() &&
                                    maintenanceOrder.getServicePlanItem().getProduct().getId().equals(servicePlanItem.getHigherLevelCode()))
                            .findFirst().orElse(null);
                    if (maintenanceOrder1 != null) {
                        servicePlanItem.setRelevanceWorkOrder(maintenanceOrder1.getId());
                    }
                });
        return maintenanceOrders;

    }

    /**
     * 根据方案生成工单（内外协服务门店确认）
     * @param servicePlan
     */
    public List<MaintenanceOrder> servicePlanCreateMaintenanceService(ServicePlan servicePlan) {
        boolean isPickUpCar = !isPickUpCar(servicePlan);
        List<MaintenanceOrder> maintenanceOrders = servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem -> servicePlanItem.isServiceState() &&
                        ("20".equals(servicePlanItem.getProduct().getProductGroup().getId()) || servicePlanItem.isProductRule()))
                .map(servicePlanItem -> maintenanceOrderService.planCreateCommonWorkOrder(servicePlan, isPickUpCar, servicePlanItem,MaintenanceOrder.WORK_ORDER_INNER))
                .collect(Collectors.toList());

        if (maintenanceOrders.isEmpty())  return null;

//        List<MaintenanceOrder> maintenanceOrders
//                = this.invoke("fn.maintenance.createMaintenanceOrders",MapUtil.mapper("maintenanceOrders",list));

        //回写绑定关系（配件绑定工单）
        servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem->servicePlanItem.getHigherLevelCode() != null)
                .forEach(servicePlanItem->{
            MaintenanceOrder maintenanceOrder1 = maintenanceOrders.stream()
                    .filter( maintenanceOrder -> servicePlanItem.isServiceState() &&
                            maintenanceOrder.getServicePlanItem().getProduct().getId().equals(servicePlanItem.getHigherLevelCode()) )
                    .findFirst().orElse(null);
            if(maintenanceOrder1 != null){
                servicePlanItem.setRelevanceWorkOrder(maintenanceOrder1.getId());
            }
        });
        return maintenanceOrders;


    }

    /**
     * 当前门店是否已接车
     * @param servicePlan
     * @return
     */
    public boolean isPickUpCar(ServicePlan servicePlan) {
        Object obj = null;
        if(servicePlan.checkInnerServicePlan()){ //基地方案，需要内协助接车
            obj = new JSONObject();
        }else{
            obj = SpringManager.getBean(PickUpCarService.class).findValidatePickUpCarByFnCustomerExpand(servicePlan.getBelongDept(),servicePlan.getFnCustomerExpand());
        }
        if(obj == null) return false;
        return true;
    }


    /**
     * 终止
     * @param simpleRequest
     * @return
     */
    public ServicePlan termination(SimpleRequest simpleRequest){
        ServicePlan servicePlan = simpleRequest.getO(ServicePlan.class);
        //检查能否终止
        checkTerminationCondition(simpleRequest, servicePlan);
        //自动归还
        checkAndReturnStock(servicePlan);
        //获取异业信息
        JSONArray crossInfo = checkCrossInfo(servicePlan);
        //清空定损方案号
        clearOrderNumber(servicePlan);
        //设置操作员
        servicePlan.setOperator1(servicePlan.getOperator1() == null ? getPerson(simpleRequest) : servicePlan.getOperator1());

        if(servicePlan.getConfirmDate() == null){
            //确认前终止
            servicePlan = terminationBeforeConfirm(servicePlan);
        }else {
            //确认后终止
            servicePlan = terminationForConfirm(servicePlan);
        }
        //清空异业
        clearCrossInfo(servicePlan, crossInfo);

        //添加不终止流程的报错信息
        errorMsg(servicePlan);

        //基地方案回写门店方案日志
        reWriteSourcePlan(servicePlan, "内协终止");

        //为了防止删除掉的原定损商品整单终止后没有全部清除,现在做的保底
        //清空定损方案号-整单终止后直接清除全部定损方案号
        terminationClearLossQuotationPlan(servicePlan);

        servicePlan.setWrite(true);
        //如果是质检状态终止 同步推送
//        if ("qualityTest".equals(state)){
//            planPushApp(servicePlan.getState(), servicePlan);
//        }
        return servicePlan;
    }

    /**
     * 彻底清除定损单方案号
     * @param servicePlan
     */
    private void terminationClearLossQuotationPlan(ServicePlan servicePlan) {
        if (!"LossQuotation".equals(servicePlan.getSourceBusinessType()))return;
        String sourceFrom = servicePlan.getSourceFrom();
        LossQuotation lossQuotation = lossQuotationRepository.findOne(sourceFrom);
        if (!"termination".equals(servicePlan.getState())){
            if (Objects.equals("B",lossQuotation.getOrderType().getCode())) {
                throw new RuntimeException("委托定损生成的服务单无法部分终止");
            }
            return;
        }
        //1.查询定损单有方案标记等于当前方案的商品
        List<Product> products = lossQuotation.getLossQuotationItems()
                .stream()
                .filter(lossQuotationItem -> servicePlan.getId().equals(lossQuotationItem.getServicePlan()))
                .map(LossQuotationItem::getProduct)
                .collect(Collectors.toList());
        if (products.isEmpty())return;

        //2.终止这些商品
        try {
            SpringManager.getBean(LossQuotationService.class).writeBackLossQuotation(products,
                    sourceFrom);
        } catch (Exception e) {
            throw new RuntimeException("清空定损报价的服务方案号失败!!!" +e);
        }
    }


    private void errorMsg(ServicePlan servicePlan) {
        List<ExternalInquiry> externalInquiryList = SpringManager.getBean(ExternalInquiryRepository.class).findBySourceBusinessKey(servicePlan.getId());
        if (externalInquiryList!=null&&externalInquiryList.size()>0){
            externalInquiryList.forEach(externalInquiry -> {
                if (!(externalInquiry.getState().equals("cancel")||externalInquiry.getState().equals("approve")))
                    servicePlan.addErrorMsg("终止成功。存在未完成的外采询价单，单号:" + externalInquiry.getId());
                //throw new RuntimeException("存在未完成的外采询价单，外采询价单号:" + externalInquiry.getId());
            });
        }
    }

    private void clearCrossInfo(ServicePlan servicePlan, JSONArray crossInfo) {
        List<ServicePlanItem> collect = servicePlan.getServicePlanItems().stream().filter(servicePlanItem -> servicePlanItem.getCrossIC() != null).collect(Collectors.toList());
        if (collect.isEmpty())return;
        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            if (crossInfo.contains(servicePlanItem.getId())) {
                clearCross(servicePlanItem);
            }
        });
        collect = servicePlan.getServicePlanItems().stream().filter(servicePlanItem -> servicePlanItem.getCrossIC() != null).collect(Collectors.toList());
        //清空核销
        if (collect.isEmpty())servicePlan.setVerification(null);

    }

    /**
     * 确认后终止
     * @param servicePlan
     * @return
     */
    private ServicePlan terminationForConfirm(ServicePlan servicePlan) {
        //判断是否存在有效终止商品
        List<ServicePlanItem> servicePlanItems = checkTerminationItem(servicePlan);
        //具体终止操作
        servicePlan = terminationAfterConfirm(servicePlan);
        //终止写完工日志
        terminationWriteFinishLogger(servicePlan, servicePlanItems);
        //通知来源处理单据
        deletePRByPlanEnd(servicePlan);
        return servicePlan;
    }

    /**
     * 检查是否能够终止
     *
     * @param servicePlan
     * @return 有效终止商品
     */
    private List<ServicePlanItem> checkTerminationItem(ServicePlan servicePlan) {
        //判断是否异业
//            servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
//                if (servicePlanItem.getCrossIC()!=null&&servicePlanItem.isSelected()) throw new RuntimeException("商品:"+servicePlanItem.getProduct().getId()+"["+servicePlanItem.getProduct().getName()+"]存在异业合作,需要先取消异业合作才能终止");
//            });
        //当前终止数和之前终止数一样的取消勾选
        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            if(servicePlanItem.isSelected() && (servicePlanItem.getQtyEnd() == servicePlanItem.getQtyEndTemp() || !servicePlanItem.isServiceState()))
                servicePlanItem.setSelected(false);
        });
        //判断有无终止商品
        List<ServicePlanItem> servicePlanItems = servicePlan.getServicePlanItems().stream().filter(servicePlanItem -> {
            return servicePlanItem.isSelected() && servicePlanItem.getTerminationDate() == null;
        }).collect(Collectors.toList());
        if(servicePlanItems.size() == 0 ) throw new RuntimeException("无有效的终止商品");
        //判断是否需要判断有要货 2021年10月18日 18:03:34 取消控制 tapdID1002553
//            if (servicePlan.getConfirmDate()!=null&&servicePlan.getInsuranceDiscounts()==null){
//                List<ServicePlanItem> needItems = servicePlanItems.stream().filter(servicePlanItem -> {
//                    return "10".equals(servicePlanItem.getProduct().getProductGroup().getId());
//                }).collect(Collectors.toList());
//                if (needItems.size()>0){
//                    List<ProductRequire> productRequireList = SpringManager.getBean(ProductRequireRepository.class).findAllBySource(servicePlan.getId());
//                    productRequireList.stream().forEach(productRequire -> {
//                        productRequire.getProductRequireItems().stream().forEach(productRequireItem -> {
//                            needItems.stream().forEach(needItem->{
//                                if (needItem.getProduct().getId().equals(productRequireItem.getProduct().getId())&&("approve".equals(productRequire.getState())||"create".equals(productRequire.getState())||"repeal".equals(productRequire.getState()))){
//                                    throw new RuntimeException("请先终止对应的要货单:"+productRequire.getId());
//                                }
//                            });
//                        });
//                    });
//                }
//            }
        return servicePlanItems;
    }

    /**
     * 判断是否需要写完工日志
     * @param resultPlan 终止之后的方案
     * @param terminationItems 终止的商品
     */
    private void terminationWriteFinishLogger(ServicePlan resultPlan, List<ServicePlanItem> terminationItems) {
        //先判断终止商品是否存在需要施工但未完工的
        long workNoFinish = terminationItems.stream()
                .filter(servicePlanItem ->
                        "20".equals(servicePlanItem.getProduct().getProductGroup().getId()) && servicePlanItem.getFinishDate() == null
                ).count();
        if (workNoFinish==0)return;
        //再判断是否已经开始施工
        long working = maintenanceOrderRepository.findWorkindByServicePlan(resultPlan.getId()).size();
        if (working==0)return;
        //判断未终止的商品是否是存在未施工完成的
        long noWorking = resultPlan.getServicePlanItems().stream().filter(servicePlanItem ->
                "20".equals(servicePlanItem.getProduct().getProductGroup().getId()) && servicePlanItem.getTerminationDate() == null && servicePlanItem.getFinishDate() == null
        ).count();
        if (noWorking>0)return;
        //如果都成立 那就写完工日志
        addServicePlanLogger(resultPlan,"完成施工","");
    }

    /**
     * 验证方案是否能终止
     * @param simpleRequest
     * @param servicePlan
     */
    private void checkTerminationCondition(SimpleRequest simpleRequest, ServicePlan servicePlan) {
        JSONObject jo = simpleRequest.getJO();
        String method = simpleRequest.getRopRequestContext().getMethod();
        //质检下终止判断
        if (servicePlan.getQualityTestDate()!=null){
            if (!servicePlan.getBelongDept().getId().equals(servicePlan.getServiceDept().getId())){
                throw new RuntimeException("内协方案质检后，不能终止");
            }
            Map checkMap = MapUtil.mapper("schemeNumber", servicePlan.getId());
            if("appOrder".equals(servicePlan.getSourceBusinessType()))checkMap.put("fromOrderNumber",servicePlan.getSourceFrom());
            Object invoke = this.invoke("pi.app.ext", MapUtil.mapper(
                    "headers", MapUtil.mapper("method", "v1/order/check-is-could-stop", "action", "get"),
                    "body", checkMap
            ));
            JSONObject appResult = JSONObject.parseObject((String) invoke);
            if (appResult.getBoolean("success")){
                JSONObject data = appResult.getJSONObject("data");
                if (!data.getBoolean("isCouldStop"))
                    throw new RuntimeException("当前方案不可终止");
            }else {
                throw new RuntimeException("接口请求有误:"+(String) invoke);
            }
        }
        //判断E服务
        if (servicePlan.getInsuranceDiscounts()!=null && !jo.containsKey("appFlage")) throw new RuntimeException("e服务订单只能在APP端终止");
        if (PLATFORM_OUT_ORDER.contains(servicePlan.getChannel().getName()) && !"fn.appServer.terminateServicePlan".equals(method))throw new RuntimeException("商品属于定制款商品，不允许在erp发起终止操作，请前往黑盒订单详情页进行操作");
        if(servicePlan.getOldFrameSourceFrom() == null && !servicePlan.getBelongDept().getId().equals(servicePlan.getServiceDept().getId()))
            throw new RuntimeException("当前门店不具备终止该方案权限，联系对应门店进行终止");

        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            if(servicePlanItem.isSelected() && servicePlanItem.getTerminationDate() == null && "ServicePlanItem.assistType.inner".equals(servicePlanItem.getAssistType().getId())){
                throw new RuntimeException("该商品已转内协,无法终止，请联系对应内协门店，商品：" + servicePlanItem.getProduct().getName());
            }

            if(servicePlanItem.isSelected() && servicePlanItem.getTerminationDate() == null && "ServicePlanItem.assistType.outer".equals(servicePlanItem.getAssistType().getId())){
                throw new RuntimeException("转外协商品，不能在方案界面终止，请在外协工单界面操作，商品：" + servicePlanItem.getProduct().getName());
            }
        });

    }

    /**
     * 检查异业信息并清空
     * @param servicePlan
     */
    private JSONArray checkCrossInfo(ServicePlan servicePlan) {
        AtomicBoolean clearCrossFlag = new AtomicBoolean(false);
        JSONArray result = new JSONArray();
        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            if (servicePlanItem.getCrossIC() != null && servicePlanItem.isSelected()) {
                if (servicePlanItem.getQtyEndTemp()!=servicePlanItem.getSaleQty())throw new RuntimeException(servicePlanItem.getProduct().getId()+":选定商品为异业项目，仅限整单终止");
                clearCrossFlag.set(true);
//                clearCross(servicePlanItem);
                result.add(servicePlanItem.getId());
            }
        });
        if (clearCrossFlag.get()){
            addServicePlanLogger(servicePlan,"清空异业信息","触发清空异业信息");
        }
        return result;
    }

    public void clearCross(ServicePlanItem servicePlanItem) {
        double qtyEndTemp = servicePlanItem.getQtyEndTemp();
        servicePlanItem.setCrossIC(null);
        //清空价格信息
        servicePlanItem.setDeductionUnit(0);//平台结算门店单价
        servicePlanItem.setExchanceCode(null);
        servicePlanItem.setQtyExchanceCode(0);
        servicePlanItem.setQtyExchanceAmount(0);
        servicePlanItem.setDeductionAmount(0);//平台结算门店金额
        servicePlanItem.setCrossPriceCost(0);//合作成本价
        servicePlanItem.setCrossCustomerPrice(servicePlanItem.getSalesAmount());//客户应付
        servicePlanItem.setCrossAccountPrice(0);//赋能结算价
        servicePlanItem.setRealPayAmount(0);
        servicePlanItem.setPftPriceUnit(servicePlanItem.getPriceUnit());
        servicePlanItem.setMatchFlag(false);
        servicePlanItem.setDiscountAmount(0);//折扣金额
    }

    public void addServicePlanLogger(ServicePlan servicePlan,String operate,String remark){

        beforeLogger(servicePlan, operate);

        Map loggerRequest = MapUtil.mapper(
                "businessKey",servicePlan.getInnerBusinessKey(),
                "businessType",servicePlan.getInnerBusinessType(),
                "operate",operate,
                "oaFlag",false,
                "remark",remark
        );
        this.invoke("ir.logger.add",loggerRequest);
    }

    /**
     * 记录服务方案日志，可记录指定的操作员
     * @param servicePlan
     * @param operate
     * @param remark
     * @param operatorId
     */
    public void addServicePlanLogger(ServicePlan servicePlan,String operate,String remark,String operatorId){
        beforeLogger(servicePlan, operate);

        Map loggerRequest = MapUtil.mapper(
                "businessKey",servicePlan.getInnerBusinessKey(),
                "businessType",servicePlan.getInnerBusinessType(),
                "operate",operate,
                "oaFlag",false,
                "remark",remark,
                "operator_id",operatorId
        );
        this.invoke("ir.logger.add",loggerRequest);
    }

    private void beforeLogger(ServicePlan servicePlan, String operate) {
        if (operate==null)return;

        switch (operate){
            case "质检完成":
                reWriteSourcePlan(servicePlan, "内协完成");
                break;
                default:
                    break;
        }
    }

    public void addServicePlanLogger(Model model,String operate,String remark,Integer UID){
        apesLoggerService.sendSynEvent("event:ir.logger.create",
                MapUtil.mapper(
                        "businessType", model.getInnerBusinessType(),
                        "businessKey", model.getInnerBusinessKey(),
                        "operate", operate,
                        "workPostName",null,
                        "remark",remark,
                        "operator_id", UID)
        );
    }
    public void addServicePlanLogger(Model model,String operate,String remark){
        apesLoggerService.sendSynEvent("event:ir.logger.create",
                MapUtil.mapper(
                        "businessType", model.getInnerBusinessType(),
                        "businessKey", model.getInnerBusinessKey(),
                        "operate", operate,
                        "workPostName",null,
                        "remark",remark)
        );
    }
    public void addServicePlanLogger(Model model, String operate, String remark, User user){
        if (user==null){
            addServicePlanLogger(model,operate,remark);
        }else {
            addServicePlanLogger(model,operate,remark,user.getId());
        }

    }

    private void checkAndReturnStock(ServicePlan servicePlan) {
        JSONArray returnArray = new JSONArray();
        List<ServicePlanItem> selectItems = servicePlan.getServicePlanItems().stream().filter(ServicePlanItem::isSelected).filter(servicePlanItem -> servicePlanItem.getProduct().getProductGroup().getId().equals("10")).collect(Collectors.toList());
        if (selectItems.size()==0)return;
        selectItems.forEach(servicePlanItem -> {
            double realSaleQty = servicePlanItem.getSaleQty() - servicePlanItem.getQtyEnd();
            double commonReturn = realSaleQty - servicePlanItem.getQtyReceive();
            double nowEndQty = servicePlanItem.getQtyEndTemp()-servicePlanItem.getQtyEnd();
            if (commonReturn<nowEndQty){
                double returnNumber = nowEndQty - commonReturn;
                JSONObject returnJson = new JSONObject();
                returnJson.put("id",servicePlanItem.getId());
                returnJson.put("productId",servicePlanItem.getProduct().getId());
                returnJson.put("location",servicePlanItem.getLocation().getId());
                returnJson.put("carLicense",servicePlan.getFnCustomerExpand().getCarLicense());
                returnJson.put("returnNumber", returnNumber);
                returnJson.put("planId", servicePlan.getId());
                returnJson.put("state", servicePlan.getState());
                returnArray.add(returnJson);
                clearQualityTest(servicePlanItem);
                servicePlanItem.setQtyReceive(servicePlanItem.getQtyReceive()-returnNumber);
            }
        });
        if (!returnArray.isEmpty())this.invoke("stock.productReturn.autoReturn", returnArray);
    }

    /**
     * 清空质检
     * @param servicePlanItem
     */
    private void clearQualityTest(ServicePlanItem servicePlanItem) {
        servicePlanItem.setFinishDate(null);
        servicePlanItem.setQualityTestDate(null);
        servicePlanItem.setQualityFlag(false);
        servicePlanItem.setQualityTestUid(null);
    }

    /**
     * 清空定损单上得服务单号
     * @param servicePlan 服务方案号
     */
    private void clearOrderNumber(ServicePlan servicePlan) {
        if (!"LossQuotation".equals(servicePlan.getSourceBusinessType()))return;
        //得到要终止的明细商品 (Collectors.toCollection(ArrayList::new));
        //得到此次终止得商品信息
        List<ServicePlanItem> servicePlanItems;
        if(servicePlan.getConfirmDate() == null){
            servicePlanItems = new ArrayList<>(servicePlan.getServicePlanItems());
        }else {
            servicePlanItems = servicePlan.getServicePlanItems().stream().filter(servicePlanItem -> {
                return (servicePlanItem.isSelected() && servicePlanItem.getTerminationDate() == null)
                        || (servicePlanItem.getQtyEnd()>0 && servicePlanItem.getTerminationDate() == null)
                        || (servicePlanItem.getQtyEnd()>0 && servicePlanItem.getSaleQty()-servicePlanItem.getQtyReceive()-servicePlanItem.getQtyEnd()>0)
                        || (servicePlanItem.getQtyEnd()>0 && servicePlanItem.isSelected());
            }).collect(Collectors.toList());
        }
        if (servicePlanItems.size() == 0) {
            return;
        }
        List<Product> products = servicePlanItems.stream().map(
                ServicePlanItem::getProduct
        ).collect(Collectors.toList());
        try {
            SpringManager.getBean(LossQuotationService.class).writeBackLossQuotation(products,
                    servicePlan.getSourceFrom());
        } catch (Exception e) {
            throw new RuntimeException("清空定损报价的服务方案号失败!!!" +e);
        }
    }

    /**
     *方案确认前终止
     * @param servicePlan
     * @return
     */
    private ServicePlan terminationBeforeConfirm(ServicePlan servicePlan){
        if(servicePlan.checkToInquiry() || servicePlan.checkToPriceAudit() || servicePlan.checkToTechAudit())
            throw new RuntimeException("当前状态不允许终止");

        servicePlan.setTerminationDate(new Date());
        servicePlan.setState("termination");
        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            servicePlanItem.setTerminationDate(new Date());
            servicePlanItem.setTerminationUid(servicePlan.getOperator1());
            servicePlanItem.setQtyEnd(servicePlanItem.getSaleQty());
            servicePlanItem.setUnitClient(null);  // 【服务方案-异业合作】终止时自动清空已选择的单位客户
        });
        ServicePlan originServicePlan = findOriginServicePlanByCurrentServicePlan(servicePlan);
        if(originServicePlan != null){
            terminationBeforeConfirm(originServicePlan);
        }

        //内协情况可能存在一方已经确认，所以如果存在方案走确认前终止，工单也要处理（只存在整单内协情况下，对方不产生任何账目上问题，处理单据）
        if(servicePlan.getConfirmDate() != null){
            servicePlan.getServicePlanItems().forEach(servicePlanItem -> servicePlanItem.setSelected(true));
            terminationCurrentMaintenanceOrderByServicePlan(servicePlan);
            confirmToApp(servicePlan);//终止来源方案时,通知app
        }


        // TAPD：ID1051234 问题新增代码
        if (Objects.isNull(originServicePlan) && servicePlan.getConfirmDate() == null ) {
            confirmToApp(servicePlan);
        }

        // 回写方案明细状态
        servicePlan.getServicePlanItems().forEach(item ->{
            item.setState("termination");  // 确认前终止,所有明细终止
        });
        this.submitSynGYSXJD(servicePlan.getId());
        return updateOnly(servicePlan);
    }



    /**
     *方案确认后终止
     * @param servicePlan
     * @return
     */
    public ServicePlan terminationAfterConfirm(ServicePlan servicePlan){
        servicePlan = terminationServicePlan(servicePlan); //终止方案
        return servicePlan;
    }


    /**
     * 验证是否能够终止
     * @param servicePlan
     */
    private void checkCanTermination(ServicePlan servicePlan) {
        servicePlan.getServicePlanItems().stream()
                .filter(ServicePlanItem::isSelected)
                .forEach(servicePlanItem -> {
                    if (servicePlanItem.getQtyEndTemp() <= 0)
                        throw new RuntimeException("终止勾选商品必须大于0，商品名称：" + servicePlanItem.getProduct().getName());
                    if (servicePlanItem.getTerminationDate() != null)
                        throw new RuntimeException("终止过的商品不能终止" + servicePlanItem.getProduct().getName());
                    if (servicePlanItem.getQtyEnd() > servicePlanItem.getQtyEndTemp())
                        throw new RuntimeException("终止数量必须大于或等于上次终止数量,商品名称：" + servicePlanItem.getProduct().getName() + ",上次终止数量：" + servicePlanItem.getQtyEnd());
                });
    }

    /**
     * 人员终止
     * @param servicePlan
     * @return
     */
    public ServicePlan terminationPrimary(ServicePlan servicePlan){
        servicePlan.setState("termination");
        servicePlan.setTerminationDate(new Date());
        servicePlan.getServicePlanItems().forEach(servicePlanItem-> servicePlanItem.setTerminationFlag(true));
        return servicePlanRepository.saveAndFlush(servicePlan);
    }

    /**
     * 设置询价相关信息
     * @param servicePlan
     */
    public void setInquiryDetail(SimpleRequest simpleRequest,ServicePlan servicePlan,String operation){
        switch (operation){
            case "toInquiry":
            case "backInquiry":
                servicePlan.setToInquiryDate(new Date());
                servicePlan.setToInquiryUid(getPerson(simpleRequest));
                break;
            case "inquiryFinish":
                break;

        }
    }

    /**
     * 设置相关信息
     * @param servicePlan
     */
    private void setInformationDetail(SimpleRequest simpleRequest,ServicePlan servicePlan){
        String state = servicePlan.getState();
        switch (state){
            case "toPriceAudit":
                servicePlan.setToPriceAuditDate(new Date());
                servicePlan.setToPriceAuditUid(getPerson(simpleRequest));
                servicePlan.setPriceAuditDate(null);
                servicePlan.setPriceAuditUid(null);
                servicePlan.setBackPriceAuditDate(null);
                servicePlan.setBackPriceAuditUid(null);
                break;
            case "priceAudit":
                servicePlan.setPriceAuditDate(new Date());
                servicePlan.setPriceAuditUid(getPerson(simpleRequest));
                break;
            case "backPriceAudit":
                servicePlan.setBackPriceAuditDate(new Date());
                servicePlan.setBackPriceAuditUid(getPerson(simpleRequest));
                break;
            case "toTechAudit":
                servicePlan.setToTechnicalAuditDate(new Date());
                servicePlan.setToTechnicalAuditUid(getPerson(simpleRequest));
                break;
            case "techAudit":
                servicePlan.setTechnicalAuditDate(new Date());
                servicePlan.setTechnicalAuditUid(getPerson(simpleRequest));
                break;
            case "backTechAudit":
                servicePlan.setBackTechnicalAuditDate(new Date());
                servicePlan.setBackTechnicalAuditUid(getPerson(simpleRequest));
                break;
            case "toInquiry":
            case "backInquiry":
                servicePlan.setToInquiryDate(new Date());
                servicePlan.setToInquiryUid(getPerson(simpleRequest));
                break;
            case "submission":
                servicePlan.setSubmissionDate(new Date());
                servicePlan.setSubmissionUid(getPerson(simpleRequest));
                break;
            case "goBack":
                servicePlan.setGoBackDate(new Date());
                servicePlan.setGoBackUid(getPerson(simpleRequest));
                break;
            case "confirm":
                servicePlan.setConfirmDate(new Date());
                servicePlan.setConfirmUid(servicePlan.getOperator1() != null ? servicePlan.getOperator1() :getPerson(simpleRequest));
                break;
            case "inquiryFinish":
                break;
            case "qualityTest":
                servicePlan.setQualityTestDate(new Date());
                servicePlan.setQualityTestUid(getPerson(simpleRequest));
                break;
                default:
                    throw new RuntimeException("发生未知错误，该操作无效");
        }
    }

    /**
     * changeFalge   ture： 减少可用数  false :增加可用数
     * @param servicePlan
     * @param changeFalge
     * @param remarks
     */
    private void dealFrozenQty(ServicePlan servicePlan,boolean changeFalge,String remarks) {
        servicePlan.getServicePlanItems().stream().filter(servicePlanItem->{
            return "10".equals(servicePlanItem.getProduct().getProductGroup().getId()) && servicePlanItem.isServiceState();
        }).forEach((item)->{
            productAccountService.setProductFrozen(
                    item.getProduct(),item.getLocation(),
                    item.getUom(),
                    changeFalge == true ?item.getSaleQty():(-item.getSaleQty()),
                    servicePlan.getInnerBusinessType(), servicePlan.getId(), item.getId(), remarks,
                    item.getLocation().getCompany(),servicePlan.getInnerBusinessType(),servicePlan.getInnerBusinessKey(),item.getInnerBusinessKey()
            );
        });
    }

    /**
     * 方案确认未必产生要货，整单内协情况，第二次确认才产生要货
     * @param servicePlan
     */
    private void requireGoods(ServicePlan servicePlan,SimpleRequest request) {

        if (!servicePlan.getBelongDept().getId().equals(servicePlan.getServiceDept().getId())) return;

        //1.做方案一方生成要货
        //2.初步过滤需要要货商品
        List<ServicePlanItem> require = filterNeedRequireItems(servicePlan);

        if (require == null) return;

        //停产下市商品
        List<Map> checkProductState = require.stream().filter(servicePlanItem -> {
            return "2".equals(servicePlanItem.getProduct().getState());
        }).map(servicePlanItem -> {
            return MapUtil.mapper("qty", servicePlanItem.getSaleQty(), "productId", servicePlanItem.getProduct().getId(), "productName", servicePlanItem.getProduct().getName());
        }).collect(Collectors.toList());
        //3.对一些要货商品，仓库等条件进行控制
        checkShutDownProduct(MapUtil.mapper("NEW_DEPT_ID", servicePlan.getBelongDept().getId(), "productList", checkProductState)); //检测当前门店是否需要要货，要货的进行检测

        try {
            SpringManager.getBean(StoreService.class).judgeFCKBJ(servicePlan.getServicePlanItems().stream().findFirst().orElse(null).getLocation());
        } catch (Exception e) {
            throw new RuntimeException("存在要货，已封库，无法确认方案!!!");
        }

        //4.发起要货
        ServicePlan requirePlan = new ServicePlan();
        BeanUtils.copyProperties(servicePlan,requirePlan, "version","innerBusinessKey","servicePlanItems");
        requirePlan.setServicePlanItems(require);
        List<ProductRequire> requires = invoke("stock.productRequireService.externalCreate", MapUtil.mapped(requirePlan));

        // 是否需要审核要货
        if (servicePlan.isPromptConfirm()) {
            requires.forEach(singleRequire -> {
                this.invoke("stock.productRequire.approve", MapUtil.mapped(singleRequire));
            });

        }
    }

    private List<ServicePlanItem> filterNeedRequireItems(ServicePlan servicePlan) {
        List<ServicePlanItem> list = servicePlan.getServicePlanItems().stream().filter(servicePlanItem -> {
            return "10".equals(servicePlanItem.getProduct().getProductGroup().getId())
                    && servicePlanItem.isServiceState()
                    && !servicePlanItem.getLocation().getUsage().isProductRule();
        }).collect(Collectors.toList());
        if (list.size() == 0) return null;
        List<ServicePlanItem> require = new ArrayList();
        //写上要货数量
        for (ServicePlanItem servicePlanItem : list) {
            Stock stock = stockRepository.findByProductAndLocation(servicePlanItem.getProduct(),servicePlanItem.getLocation());
            double requireGoodsAmount = (stock == null) ? (-servicePlanItem.getSaleQty()) : Arith.sub(stock.getMarketableQtyFaDs(),servicePlanItem.getSaleQty() -servicePlanItem.getQtyEnd());
            if (requireGoodsAmount < 0) {
                double qty = Math.abs(requireGoodsAmount) >= (servicePlanItem.getSaleQty() - servicePlanItem.getQtyEnd()) ? (servicePlanItem.getSaleQty() - servicePlanItem.getQtyEnd()) : Math.abs(requireGoodsAmount);
                servicePlanItem.setQtyRequire(qty);
                require.add(servicePlanItem);
            }
        }
        return require;
    }

    private String throwClassNameError(Exception e) {
        for (StackTraceElement stackTraceElement : e.getStackTrace()) {
            if (this.getClass().getName().equals(stackTraceElement.getClassName())) {
                return "生成要货有误:"+e.getMessage()+";"+this.getClass().getSimpleName()+":"+stackTraceElement.getLineNumber();
            }
        }
        return e.getMessage();
    }

    /**
     * 写MongoDB日志
     * @param collectionName
     * @param servicePlanId
     * @param data
     * @param note
     */
    private void writeDB(String collectionName,String servicePlanId, Map data,String note){
        if (false)return;
        Document document = new Document();
        document.put("servicePlanId", servicePlanId);
        document.put("data", data);
        document.put("note",note);
        mongoTemplate.getCollection(collectionName).insertOne(document);
    }

    /**
     * 方案确认前的外采要货，开始区分库存
     * @param servicePlan
     * @param values
     * @param
     */
    private void structRequireGoods(ServicePlan servicePlan, List<ServicePlanItem> values) {
        ProductRequire productRequire = new ProductRequire();
        productRequire.setWriteBackQtyRequire(false);  // 方案确认生成的审核要货单不回写（防止hibernate出错）
        productRequire.setChannel(servicePlan.getChannel());
        productRequire.setOperator1(servicePlan.getOperator1());
        productRequire.setSource(servicePlan.getId());
        productRequire.setSourceBusinessType(servicePlan.getBusinessType());
        productRequire.setSourceBusinessTypeName(servicePlan.getBusinessTypeName());
        productRequire.setLocation(values.stream().findFirst().get().getLocation());
        productRequire.setStore(getBean(StoreRepository.class).findByDept(servicePlan.getServiceDept()));
        productRequire.setCustomerExpand(servicePlan.getFnCustomerExpand());
        // productRequire.setPurchaseOrg(values.stream().findFirst().get().getOrganization());
        productRequire.setCompany(values.stream().findFirst().get().getLocation().getCompany());
        productRequire.setPlatform(values.stream().findFirst().get().getPlatform());
        productRequire.setCreator(servicePlan.getConfirmUid().getId());
        productRequire.setZKXZBJ(1); //则需要设置选择仓库  仓库选择标记(0:区域仓;1:总仓)
        boolean flag = false;
        for (ServicePlanItem externalInquiryItem : values) {
            Stock stock = stockRepository.findByProductAndLocation(externalInquiryItem.getProduct(),externalInquiryItem.getLocation());
//            writeDB(CONST_REQUIRE_COLLECTION_NAME,servicePlan.getId(),MapUtil.mapped(stock),"商品库存帐");
            double requireGoodsAmount = (stock == null) ? (-externalInquiryItem.getSaleQty()) : Arith.sub(stock.getMarketableQtyFaDs(),externalInquiryItem.getSaleQty() -externalInquiryItem.getQtyEnd());
            if(requireGoodsAmount < 0){
                flag = true;
                ProductRequireItem productRequireItem = new ProductRequireItem();
                productRequireItem.setProductRequire(productRequire);
                productRequireItem.setCompany(externalInquiryItem.getLocation().getCompany());
                productRequireItem.setProduct(externalInquiryItem.getProduct());
                productRequireItem.setUom(externalInquiryItem.getUom());
                productRequireItem.setSupplier(externalInquiryItem.getSupplier());
                productRequireItem.setQtyRequire(
                        Math.abs(requireGoodsAmount) >= (externalInquiryItem.getSaleQty() -externalInquiryItem.getQtyEnd()) ? (externalInquiryItem.getSaleQty() -externalInquiryItem.getQtyEnd()) : Math.abs(requireGoodsAmount)
                ); // 要货数量
                productRequireItem.setCommodityInquiryOrderId(externalInquiryItem.getOldInquiryNumber());
                productRequireItem.setExpectedArrivalTime(externalInquiryItem.getExpectedArrivalTime());
                if (StringUtils.hasText(productRequireItem.getCommodityInquiryOrderId())) {
                    productRequireItem.setSourceState(enumerationRepository.findAll(JpaDsl.toCriteriaByEq("type.id", "supplyStatus", "code", externalInquiryItem.getInquiryGooodsState())).stream().findFirst().orElse(null));
                } else {
                    productRequireItem.setSourceState(enumerationRepository.findOne("003334"));
                }
                productRequire.getProductRequireItems().add(productRequireItem);
                if ("true".equals(externalInquiryItem.getPriceForward())){
                    productRequireItem.setSpId(externalInquiryItem.getUniqueValue());
                    productRequireItem.setChannelType(1);
                    productRequireItem.setSupplier(externalInquiryItem.getSupplier());
                }
            }
        }
        if(flag){
            productRequire.set_creator(servicePlan.getConfirmUid());
            productRequire.setCreator(servicePlan.getConfirmUid().getId());
            List<User> userInfo = SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id", servicePlan.getConfirmUid().getId()));
            if (userInfo.size() == 0) throw new RuntimeException("请先创建用户, 人员: " + servicePlan.getConfirmUid().getId());
            productRequire.setUserId(userInfo.get(0).getId().toString());
            productRequire = this.invoke("stock.productRequire.create", productRequire); //新增
            productRequire.setApproveId(servicePlan.getConfirmUid());
            productRequire.setApproveDate(new Date());
            userInfo = SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id", productRequire.getApproveId().getId()));
            if (userInfo.size() == 0) throw new RuntimeException("请先创建用户, 人员: " + servicePlan.getConfirmUid().getId());
            productRequire.setUserId(userInfo.get(0).getId().toString());
            if (servicePlan.isPromptConfirm())this.invoke("stock.productRequire.approve", productRequire); //审批
        }
//        writeDB(CONST_REQUIRE_COLLECTION_NAME,servicePlan.getId(),MapUtil.mapper("productRequireId",productRequire.getId(),"flag",flag+"","productId",values.get(0).getProduct().getId()),"现金外采生成要货");

    }

    /**
     * @param servicePlan   原方案数据
     * @param values  分组后的数据
     * @promptConfirm  判断是否自动审核定损单
     * @chooseWarehouse 仓库选择标记(0:区域仓;1:总仓)
     */
    private void structRequireGoods(ServicePlan servicePlan, List<ServicePlanItem> values,SimpleRequest request) {
        Boolean flag = false;
        ProductRequire productRequire = new ProductRequire();
        productRequire.setWriteBackQtyRequire(false);  // 方案确认生成的审核要货单不回写（防止hibernate出错）
        productRequire.setChannel(servicePlan.getChannel());
        productRequire.setOperator1(servicePlan.getOperator1());
        productRequire.setSource(servicePlan.getId());
        productRequire.setSourceBusinessType(servicePlan.getBusinessType());
        productRequire.setSourceBusinessTypeName(servicePlan.getBusinessTypeName());
        productRequire.setLocation(values.stream().findFirst().get().getLocation());
        productRequire.setCustomerExpand(servicePlan.getFnCustomerExpand());
       // productRequire.setPurchaseOrg(values.stream().findFirst().get().getOrganization());
        productRequire.setCompany(values.stream().findFirst().get().getLocation().getCompany());
        productRequire.setPlatform(values.stream().findFirst().get().getPlatform());
        productRequire.setCreator(servicePlan.getConfirmUid().getId());
        productRequire.setStore(getBean(StoreRepository.class).findByDept(servicePlan.getServiceDept()));
        //chooseWarehouse  则需要设置选择仓库  仓库选择标记(0:区域仓;1:总仓)
        productRequire.setZKXZBJ(servicePlan.getChooseWarehouse());
        for(ServicePlanItem servicePlanItem : values){
            Stock stock = stockRepository.findByProductAndLocation(servicePlanItem.getProduct(),servicePlanItem.getLocation());
//            if (stock!=null)writeDB(CONST_REQUIRE_COLLECTION_NAME,servicePlan.getId(),MapUtil.mapped(stock),"商品库存帐");
            double requireGoodsAmount = (stock == null) ? (-servicePlanItem.getSaleQty()) : Arith.sub(stock.getMarketableQtyFaDs(),servicePlanItem.getSaleQty() -servicePlanItem.getQtyEnd());
//            writeDB(CONST_REQUIRE_COLLECTION_NAME,servicePlan.getId(),MapUtil.mapper(
//                    "requireGoodsAmount",requireGoodsAmount,
//                    "stock",stock == null?"无库存帐":stock.getId(),
//                    "values",values.size(),
//                    "MarketableQtyFaDs",stock == null?"无库存帐":stock.getMarketableQtyFaDs()+"",
//                    "Product",servicePlanItem.getProduct().getId(),
//                    "Location",servicePlanItem.getLocation().getId(),
//                    "getSaleQty",-servicePlanItem.getSaleQty()),"requireGoodsAmount数量");

            Boolean appOrder = false;
            //app下单无要货 临时解决方案 2021年10月13日 12:38:06
            List classifyList = new ArrayList();
            classifyList.add(MapUtil.mapper("productId",servicePlanItem.getProduct().getId()));

            if(classifyList.size() !=0&&"app订单(车险优惠)".equals(servicePlan.getSourceBusinessTypeName())){
                JSONObject json = new JSONObject();
                json.put("NEW_DEPT_ID", servicePlan.getBelongDept().getId());
                json.put("OLD_DEPT_ID", servicePlan.getBelongDept().getOrigin());
                json.put("productList", classifyList);
                JSONArray array = servicePlanDao.queryProductStoreForList(json);

                JSONArray resultList = array.stream().filter(tempJson ->{
                    JSONObject item = (JSONObject)tempJson;
                    return item.getDoubleValue("GENERAL_STOCK") + item.getDoubleValue("SUB_STOCK") + item.getDoubleValue("STOCK_AMOUNT") <= 0;
                }).collect(Collectors.toCollection(JSONArray :: new));

                if(resultList.size() != 0&&requireGoodsAmount==0)  appOrder=true;
//                writeDB(CONST_REQUIRE_COLLECTION_NAME,servicePlan.getId(),MapUtil.mapper("appOrder",appOrder,"resultList",resultList.size()),"app下单无要货 临时解决方案");
            }

            if(requireGoodsAmount < 0 ||appOrder){
                flag = true;
                ProductRequireItem productRequireItem = new ProductRequireItem();
                productRequireItem.setProductRequire(productRequire);
//                productRequireItem.setSupplier(servicePlanItem.getSupplierId());
                productRequireItem.setCompany(servicePlanItem.getLocation().getCompany());
              //  productRequireItem.setPurchaseOrg(servicePlanItem.getOrganization());
                productRequireItem.setProduct(servicePlanItem.getProduct());
                productRequireItem.setUom(servicePlanItem.getUom());
//                productRequireItem.setSupplier(servicePlanItem.getSupplierId());
                productRequireItem.setQtyRequire(
                        Math.abs(requireGoodsAmount) >= (servicePlanItem.getSaleQty() -servicePlanItem.getQtyEnd()) ? (servicePlanItem.getSaleQty() -servicePlanItem.getQtyEnd()) : Math.abs(requireGoodsAmount)
                );
                getCommodiInquireSupplier(servicePlanItem.getOldInquiryNumber(), servicePlanItem.getProduct().getId(), productRequireItem);
                productRequireItem.setCommodityInquiryOrderId(servicePlanItem.getOldInquiryNumber());
                productRequireItem.setUniqueValue(servicePlanItem.getUniqueValue());
                if (StringUtils.hasText(productRequireItem.getCommodityInquiryOrderId())) {
                    if (StringUtils.isEmpty(servicePlanItem.getInquiryGooodsState())) throw new RuntimeException("货源状态不能为空！");
                    productRequireItem.setSourceState(enumerationRepository.findOne(JpaDsl.toCriteriaByEq("type.id", "supplyStatus", "code", servicePlanItem.getInquiryGooodsState())).get());
                } else {
                    productRequireItem.setSourceState(enumerationRepository.findOne("003334"));
                }
                productRequireItem.setExpectedArrivalTime(servicePlanItem.getExpectedArrivalTime());
                productRequire.getProductRequireItems().add(productRequireItem);
                if (Objects.nonNull(servicePlanItem.getPriceForward()) && "1-2-4-5".contains(servicePlanItem.getPriceForward())){
                    productRequireItem.setSpId(servicePlanItem.getUniqueValue());
                    productRequireItem.setChannelType(Integer.valueOf(servicePlanItem.getPriceForward()));
                    productRequireItem.setSupplier(servicePlanItem.getSupplier());
                    List<PurchasingGroup> purchasingGroups = getBean(PurchasingGroupRepository.class).findDeptAndSupplier(servicePlan.getServiceDept().getId(), servicePlanItem.getSupplier().getId());
                    if (!purchasingGroups.isEmpty()) {
                        productRequireItem.setPurchasingGroup(purchasingGroups.get(0));
                    }
                    if(LogicalUtil.in(servicePlanItem.getPriceForward(), "2", "5")) {
                        productRequireItem.setOfferId(servicePlanItem.getUniqueValue());
                    }
                }
            }
        }
        if(flag){
//            PartyRole system = SpringManager.getBean(PartyRoleRepository.class).findOne("system");
            productRequire.setCreator(servicePlan.getConfirmUid().getId());
            productRequire.set_creator(servicePlan.getConfirmUid());
            List<User> userInfo = SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id", servicePlan.getConfirmUid().getId()));
            if (userInfo.size() == 0) throw new RuntimeException("请先创建用户, 人员: " + servicePlan.getConfirmUid().getId());
            productRequire.setUserId(userInfo.get(0).getId().toString());
            productRequire.setSessionId(null);
            Map map = MapUtil.mapped(productRequire);
            String postId = "";
            if(request.getSession() != null) {
                postId = request.getSession().getAttribute("workPostName", String.class);
                request.getSession().setAttribute("workPostName", "");
            }

            productRequire = this.invoke("stock.productRequire.create", map); //新增
            if ("appOrder".equals(servicePlan.getSourceBusinessType()) || servicePlan.isPromptConfirm()) {
                productRequire.setApproveId(servicePlan.getConfirmUid());
                productRequire.setApproveDate(new Date());
                userInfo = SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id", servicePlan.getConfirmUid().getId()));
                if (userInfo.size() == 0) throw new RuntimeException("请先创建用户, 人员: " + servicePlan.getConfirmUid().getId());
                productRequire.setUserId(userInfo.get(0).getId().toString());
//                userInfo = SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id", servicePlan.getConfirmUid().getId()));
                if (userInfo != null && userInfo.size() > 0)
                    productRequire.setUserId(userInfo.get(0).getId().toString());
                map = MapUtil.mapped(productRequire);
                if (request.getSession() != null) {
                    request.getSession().setAttribute("workPostName", postId);
                }
                this.invoke("stock.productRequire.approve",map); //审批
            }
        }
//        writeDB(CONST_REQUIRE_COLLECTION_NAME,servicePlan.getId(),MapUtil.mapper("productRequireId",productRequire.getId(),"flag",flag+"","productId",values.get(0).getProduct().getId(),"values",values.size()),"非现金外采生成要货");


    }

    /** 获取询价执行表供应商 */
    private void getCommodiInquireSupplier(String commodiInquireId, String productId, ProductRequireItem productRequireItem) {
        JSONObject data = piManager.synErp("spxjdService.getSPXJDZXBInfo", MapUtil.mapper("XJDH", commodiInquireId, "SPID", productId));
        data = JSONObject.parseObject(data.get("obj").toString());
        if (data.get("GYSID") != null) {
            List<ContrastPartyCode> contrastPartyCodeList = SpringManager.getBean(ContrastPartyCodeRepository.class).findAll(JpaDsl.toCriteriaByEq("gysid", data.getString("GYSID")));
            if (contrastPartyCodeList.size() == 0) {
                throw new RuntimeException("请维护角色对照表，供应商编码：" + data.getString("GYSID"));
            }
            productRequireItem.setSupplier(SpringManager.getBean(PartyRoleRepository.class).findAll(JpaDsl.toCriteriaByEq("party.id", contrastPartyCodeList.get(0).getParty().getId(), "role.id", "Supplier")).get(0));
            if (data.get("ZDID") != null) productRequireItem.setSite(SpringManager.getBean(SiteRepository.class).findOne(data.getString("ZDID")));
            if (data.get("CGZID") != null) productRequireItem.setPurchasingGroup(SpringManager.getBean(PurchasingGroupRepository.class).findOne(data.getString("CGZID")));
        }
    }


    /**
     * 获取询价商品，根据服务类型分组
     * @param servicePlan
     */
    public Map<String,List<ServicePlanItem>> getInquiryGoods(ServicePlan servicePlan){
        Map<String,List<ServicePlanItem>> groupMap = new HashMap<String,List<ServicePlanItem>>();
        PartyRole platform = SpringManager.getBean(FnCommunalService.class).getPlatform(false, true, servicePlan.getBelongDept());
        List<ServicePlanItem> list = servicePlan.getServicePlanItems().stream().filter(ServicePlanItem::isNeedInquiry).collect(Collectors.toList());
        if(list.size() == 0) throw new RuntimeException("没有需要询价的商品");
        groupMap= list.stream().collect(groupingBy((item)->{
            return  item.getServeType().getId() + platform.getId() + item.isProductRule();
        }));
        return groupMap;
    }

    /**
     * 判断该服务方案需要货商品
     *
     * @param request
     */
    public Object getRequireGoods(SimpleRequest request){
        String id  = request.get("id");
        String str = " 即将产生要货单，是否需要立即审核要货单？ ";
        JSONObject result = new JSONObject();
        result.put("title","要货单是否审核?");
        ServicePlan servicePlan = servicePlanRepository.findOne(id);
        if (servicePlan == null) throw new RuntimeException("未找到对应的服务方案单, 单号: "+id);
        List<ServicePlanItem> list = getRequireGoodsData(servicePlan);
        for (ServicePlanItem item : list) {
            if (!StringUtils.isEmpty(item.getOldInquiryNumber())) {
                str = "存在询价的要货，建议在有效期内拿货，否则会存在价格及库存变动。即将产生要货单，是否需要立即审核要货单？ ";
                result.put("content", str);
                return result;
            }
        }
        if (list.size() == 0) return "noShowConfirm";
        result.put("content",str);
        return result;
    }

    /**
     * 判断是否有异业或者需要归还的商品
     * @param request
     * @return
     */
    public JSONObject getTerminationConfirm(SimpleRequest request){
        JSONObject jo = request.getJO();
        JSONArray hour = new JSONArray();
        JSONArray work = new JSONArray();
        String str = "";
        String type = "4";
        JSONObject model = jo.getJSONObject("model");
        JSONArray servicePlanItems = model.getJSONArray("servicePlanItems");
        Boolean confirm = model.get("confirmDate")==null;
//        String str = " 确认后选中的商品项目将全部终止 ";
        List<Map> mapList = servicePlanItems.stream()
                .filter(Objects::nonNull)
                .filter(o -> ((JSONObject) o).getBoolean("selected") || confirm)
                .map(o -> {
                    JSONObject item = (JSONObject) o;
                    JSONObject product = item.getJSONObject("product");
                    JSONObject category = item.getJSONObject("category");
                    Integer saleQty = item.getInteger("saleQty");
                    JSONObject crossICP = item.getJSONObject("crossICP");
                    Integer qtyEnd = item.getInteger("qtyEnd");
                    int realSale = saleQty - qtyEnd;
                    Integer qtyReceive = item.getInteger("qtyReceive");
                    Integer qtyEndTemp = item.getInteger("qtyEndTemp")==null?0:item.getInteger("qtyEndTemp");
                    int canEnd = realSale - qtyReceive;
                    int endQty = canEnd - (qtyEndTemp - qtyEnd);
                    int nowReturnQty = endQty > 0 ? 0 : (endQty * -1);
                    boolean cross = crossICP != null;
                    if (nowReturnQty > 0) work.add(1);
                    if (cross) hour.add(1);
                    if (category.getString("id").equals("009525")) {
                        return MapUtil.mapper(
                                "product", '[' + product.getString("id") + ']' + product.getString("name"),
                                "saleQty", saleQty, "qtyReceive", item.getString("qtyReceive"),
                                "nowReturnQty", "-", "Cross", cross ? '[' + crossICP.getString("id") + ']' + crossICP.getString("name") : "-"
                        );
                    }
                    return MapUtil.mapper(
                            "product", '[' + product.getString("id") + ']' + product.getString("name"),
                            "saleQty", saleQty, "qtyReceive", item.getString("qtyReceive"),
                            "nowReturnQty", nowReturnQty, "Cross", cross ? '[' + crossICP.getString("id") + ']' + crossICP.getString("name") : "-"
                    );
                }).collect(Collectors.toList());
        JSONObject result = new JSONObject();
        if (!work.isEmpty()){
            str="选定终止的项目有材料已领用，确认终止后将全部归还至系统中";
            type="1";
        }
        if (!hour.isEmpty()){
            str="选定终止的项目有异业信息，确认终止后将清空异业合作信息";
            type="2";
        }
        if ((!hour.isEmpty())&&!work.isEmpty()){
            str="选定终止的项目有材料已领用及异业合作，确认终止后材料将全部归还至系统中、异业合作信息将清空";
            type="3";
        }
        if (mapList.isEmpty())throw new RuntimeException("没有可终止明细");
        result.put("warningInfo",str);
        result.put("type",type);
        result.put("servicePlanItems",mapList);
        return result;
    }


    private List<ServicePlanItem> getRequireGoodsData(ServicePlan servicePlan) {
        return servicePlan.getServicePlanItems().stream().filter(
                    item -> {
                        boolean flg = false;
                        if ("10".equals(item.getProduct().getProductGroup().getId()) && item.isServiceState()&& item.getInnerServicePlanItem()==null
                                && !item.getLocation().getUsage().isProductRule()) {
                            Stock stock = stockRepository.findByProductAndLocation(item.getProduct(),item.getLocation());
                            double requireGoodsAmount = (stock == null) ? (-item.getSaleQty()) : Arith.sub(stock.getMarketableQtyFaDs(),item.getSaleQty());
                            if (requireGoodsAmount <0) flg = true;
                        }
                        return flg;
                    }
            ).collect(Collectors.toList());
    }

    /**
     * 要货审核查询区域仓库存
     * @param simpleRequest
     * @return
     */
    public JSONObject getRequireGoodsConfirm(SimpleRequest simpleRequest) {
        ServicePlan servicePlan = simpleRequest.getO(ServicePlan.class);
        Location location = locationRepository.findAll(JpaDsl.toCriteriaByEq(
                "depot.dept.id",servicePlan.getServiceDept().getId(),"usage.id","1")
        ).stream().findFirst().orElse(null);
        if(Objects.isNull(location) ||Objects.isNull(location.getPhyDepot())) throw new RuntimeException("该门店得所属仓库信息缺失!!!");
        String depotOrigin = location.getPhyDepot().getOrigin();
        JSONObject data = new JSONObject();
        String productIdStr = "";
        JSONArray itemArray = new JSONArray();
        List<ServicePlanItem> list = getRequireGoodsData(servicePlan);
        for (ServicePlanItem servicePlanItem : list) {
            //获取需要要货数量
            Stock stock = stockRepository.findByProductAndLocation(servicePlanItem.getProduct(),servicePlanItem.getLocation());
            double requireGoodsAmount = (stock == null) ? (-servicePlanItem.getSaleQty()) : Arith.sub(stock.getMarketableQtyFaDs(),servicePlanItem.getSaleQty());
            requireGoodsAmount = Math.abs(requireGoodsAmount) >= (servicePlanItem.getSaleQty() -servicePlanItem.getQtyEnd()) ? (servicePlanItem.getSaleQty() -servicePlanItem.getQtyEnd()) : Math.abs(requireGoodsAmount);
            JSONObject singleData = new JSONObject();
            String productId = servicePlanItem.getProduct().getId();
            productIdStr += "'" + productId + "',";
            singleData.put("PRODUCT_ID", productId);
            singleData.put("PRODUCT_NAME", servicePlanItem.getProduct().getName());
            singleData.put("qtyRequire", requireGoodsAmount);
            singleData.put("uomName", servicePlanItem.getUom().getName());
            itemArray.add(singleData);
        }
        data.put("item", itemArray);
        data.put("LOCATION_ID", location.getId());
        data.put("LOCATION_NAME", location.getName());
        data.put("productIdStr", productIdStr.substring(0, productIdStr.length() - 1));
        data.put("GSID", servicePlan.getCompany().getId());
        data.put("DDID", depotOrigin != null ? depotOrigin : location.getPhyDepot().getId());
        data.put("KQID", location.getUsage().getId());

        JSONObject getData = piManager.synErp("scmYhdService.qryQYCKC", data);
        return JSONObject.parseObject(getData.get("obj").toString());
    }

    private boolean judgeSendInquiryPurGroup(String storeId, String purchasingGroupId) {
        boolean isExistsPurchasGrouop = invoke("cm.purchasingGroupService.accordStoreIdFind", MapUtil.mapper("storeId", storeId, "purchasingGroupId", purchasingGroupId));
        return isExistsPurchasGrouop;
    }

    // 转询价 - 巴图鲁询价
    private void baturuInquireMainData(ServicePlan servicePlan, JSONObject inquireData, Map inquireOtherInfo) {
        String store = servicePlan.getBelongDept().getOrigin();
        inquireData.put("origin", servicePlan.getInnerBusinessKey());
        inquireData.put("originBusinessType", servicePlan.getInnerBusinessType());
        inquireData.put("store", store);

        List contractPersons = servicePlanRepository.findAll("SELECT (SELECT RYID FROM MAS_BJZRY@DB_OLDERP B WHERE B.BJZ = A.BJZ AND ROWNUM = 1) FROM MAS_DDXX@DB_OLDERP A WHERE DDID = '"+ store +"'");
        if (contractPersons.isEmpty() || StringUtils.isEmpty(contractPersons.get(0))) throw new RuntimeException("当前门店无报价组，询价无法获取联系人，请在老系统【地点信息】配置报价组后再转询价");
        String inquirePerson = contractPersons.get(0).toString();
        User user = new User();
        if (StringUtils.hasText(inquirePerson)) user = SpringManager.getBean(UserRepository.class).findByOrigin(inquirePerson);
        inquireData.put("publishNew", true);
        inquireData.put("contactPerson", ObjectUtils.isEmpty(user)?"":user.getName());
        inquireData.put("contactPhone", ObjectUtils.isEmpty(user)?"":user.getMobileNumber());


        Location location = locationRepository.findByDept(servicePlan.getBelongDept().getId()).get(0);
        PhyDepot phyDepot = location.getPhyDepot();
        JSONObject receiverAddress = new JSONObject();
        receiverAddress.put("location", phyDepot.getLongitude() +"," + phyDepot.getLatitude());
        receiverAddress.put("address", phyDepot.getAddress());
        inquireData.put("inquiryAddress", receiverAddress);

        // 车辆信息
        JSONArray carInfos = new JSONArray();
        JSONObject carInfo = new JSONObject();
        carInfo.put("vinCode", servicePlan.getFnCustomerExpand().getVin());
        carInfo.put("jekunModelCode", servicePlan.getFnCustomerExpand().getJekunModelCode());
        carInfo.put("carModelLabel", servicePlan.getFnCustomerExpand().getCarModelLabel());
        carInfo.put("carLicense", servicePlan.getFnCustomerExpand().getCarLicense());
        carInfo.put("nameplatePicture", inquireOtherInfo.get("nameplatePicture"));
        carInfo.put("headPicture", inquireOtherInfo.get("headPicture"));
        carInfo.put("trailPicture", inquireOtherInfo.get("trailPicture"));

        List oldQccxpzs = servicePlanRepository.findAll("SELECT QCPPMC, CHXID, QCCPMC FROM MAS_QCCXPZ@DB_OLDERP WHERE PZCXID = '"+ servicePlan.getFnCustomerExpand().getJekunModelCode() +"'");
        if (!oldQccxpzs.isEmpty()) {
            Object[] carInfosO = ((Object[])oldQccxpzs.get(0));
            carInfo.put("carBrandName", carInfosO[0]);
            carInfo.put("carSystemName", carInfosO[1]);
            carInfo.put("carManuFacturer", carInfosO[2]);
            carInfo.put("carType", carInfosO[1]);
        }
        carInfos.add(carInfo);
        inquireData.put("carInfos", carInfos);
    }

    // 转询价 - 巴图鲁询价明细
    private void baturuInquireData(ServicePlanItem item, JSONObject inquireData, PartyRole platform) {
        JSONArray inquiryDetails = new JSONArray();
        JSONObject inquiryDetail = new JSONObject();
        if ("E01".equals(item.getPartCode()) || StringUtils.hasText(item.getPartCode())) { // E01 表示高低配
            String partyName = item.getProduct().getCategory().getName().indexOf("待编译") == -1?item.getProduct().getCategory().getName():item.getPartName();
            inquiryDetail.put("partsName", partyName);
            if (!"E01".equals(item.getPartCode())) inquiryDetail.put("partsCode", item.getPartCode());
        } else {
            inquiryDetail.put("partsName", item.getProduct().getCategory().getName());
        }
        inquiryDetail.put("remark", (StringUtils.isEmpty(item.getRemarks())?"":item.getRemarks()) + (StringUtils.isEmpty(item.getPartCode())?"":item.getPartCode()));
        inquiryDetail.put("platformId", platform.getId());
        inquiryDetail.put("partsId", item.getProduct().getId());
        inquiryDetail.put("threePartyDetailCode", item.getProduct().getId());
        inquiryDetail.put("originProduct", item.getProduct().getId());
        inquiryDetail.put("pictures", this.obtainTagImages(item.getTagMapAddress()));

        inquiryDetail.put("productRule", item.isProductRule() ? 1 : 0);
        inquiryDetails.add(inquiryDetail);
        if (inquireData.containsKey("inquiryDetails")) {
            JSONArray inquiryDetailsAppend =inquireData.getJSONArray("inquiryDetails");
            inquiryDetailsAppend.addAll(inquiryDetails);
        } else {
            inquireData.put("inquiryDetails", inquiryDetails);
        }
    }


    /**
     * 创建商品询价单 尹云要求新格式
     * @param
     */
    private void createCommodityInquiry( ServicePlan servicePlan,Map<String,List<ServicePlanItem>> groupMap,PartyRole creator, Map inquireOtherInfo) {
        // 巴图鲁询价
        boolean isExistsPurGroup = judgeSendInquiryPurGroup(servicePlan.getBelongDept().getId(), findBaturuSupplier.get(0).getValue3());
        CompanyEntry companyEntry = SpringManager.getBean(CompanyEntryRepository.class).findByPartyId(servicePlan.getCompany().getParty().getId());
        boolean wantInvoiceFlag = ObjectUtils.isEmpty(companyEntry)?true:companyEntry.isWantInvoice();
        CarConfiguration carConfiguration = SpringManager.getBean(CarConfigurationRepository.class).findOne(servicePlan.getFnCustomerExpand().getJekunModelCode());
        boolean scopeCarFlag = invoke("mdm.supplierBusinessScopeService.externalCallBusinessScopeCar", MapUtil.mapper("supplierId", findBaturuSupplier.get(0).getValue(), "carlabelId", carConfiguration.getCarLabel().getId()));

        JSONObject inquireData = new JSONObject();
        if (!wantInvoiceFlag && isExistsPurGroup && scopeCarFlag) this.baturuInquireMainData(servicePlan, inquireData, inquireOtherInfo);

        JSONArray array = new JSONArray();
        PartyRole platform = SpringManager.getBean(FnCommunalService.class).getPlatform(false, true, servicePlan.getBelongDept());
        CommodityInquiryOrderService commodityInquiryOrderService = SpringManager.getBean(CommodityInquiryOrderService.class);
        groupMap.forEach((key,values)->{
            JSONObject data = new JSONObject();

            data.put("UNIQUE_ID", UUID.randomUUID().toString());
            data.put("DJLXID", "SX0");
            data.put("DJLXMC", "商品询价单");
            data.put("C_CDNM", "makeSPXJD");
            data.put("CPHM", servicePlan.getFnCustomerExpand().getCarLicense());
            data.put("LYDJHM", servicePlan.getInnerBusinessKey());
            data.put("LYDJLX", "servicePlan");
            data.put("LYDJMC","服务方案");
            ServicePlanItem servicePlanItem = values.stream().findFirst().orElse(new ServicePlanItem());
            ServeType serveType = servicePlanItem.getServeType();
            data.put("FWLXID", serveType.getId());
            data.put("FWLXMC", serveType.getName());
            data.put("DABJ", servicePlanItem.isProductRule() ? 1 : 0);
            data.put("F_GSID", servicePlan.getCompany().getId());
            data.put("GSID", servicePlan.getCompany().getId());
            data.put("PTID", platform.getId());
            data.put("PTMC", platform.getName());
            data.put("CZY", creator.getName());
            data.put("ZDR", creator.getName());
            data.put("ZDRQ_SJ", new Date());
//            data.put("RYID", creator.getId());
//            data.put("RYMC", creator.getName());
            data.put("MDID", servicePlan.getBelongDept().getOrigin());
            data.put("MDMC", servicePlan.getBelongDept().getName());
            data.put("FWMDID", servicePlan.getBelongDept().getOrigin());
            data.put("FWMDMC", servicePlan.getBelongDept().getName());
            data.put("CJHM", servicePlan.getFnCustomerExpand().getVin());
            data.put("PZCXID", servicePlan.getFnCustomerExpand().getJekunModelCode());
            data.put("PZCXMC", servicePlan.getFnCustomerExpand().getCarModelLabel());
            try {
                data.put("FWFAZDR",SpringManager.getBean(PartyRoleRepository.class).findOne(servicePlan.getCreator()).getName());
            }catch (Exception e){
                throw new RuntimeException("方案制单人实体不存在");
            }
            JSONArray itemArray = new JSONArray();
            int index = 0;
            values.forEach(item -> {
                CommodityInquiryItem commodityInquiryItem = new CommodityInquiryItem();
                commodityInquiryItem.setProductId(item.getProduct());
                commodityInquiryItem.setOriginalProductId(item.getProduct());
                commodityInquiryItem.setFitting(item.getFitting());
                commodityInquiryItem.setProductUomId(item.getUom());
                commodityInquiryItem.setSummary(item.getRemarks()==null?item.getRemarks():item.getRemarks().replace(" ",","));

                commodityInquiryItem.setSalesVolume(item.getSaleQty());
                commodityInquiryItem.setDeliverables(item.getSaleQty());
                commodityInquiryItem.setSupplyStatus(findCommotidyHY());
                commodityInquiryItem.setCompanyId(item.getLocation().getCompany());

                commodityInquiryItem.setUnitPrice(0);
                commodityInquiryItem.setSaleLimit(item.getFloorPrice());
                commodityInquiryItem.setSaleLimit(item.getFloorPrice());
                commodityInquiryItem.setInquiryType(item.getInquiryType());
                commodityInquiryItem.setMapAddress(item.getMapAddress());
                commodityInquiryItem.setPartCode(item.getPartCode());
                commodityInquiryItem.setPartName(item.getPartName());
                commodityInquiryItem.setImageSN(item.getImageSN());
                JSONObject result = new JSONObject();
                result = commodityInquiryOrderService.formatSPXJDMX(result,commodityInquiryItem);
                result.put("XH", index +1);
                itemArray.add(result);
                boolean excluClassifyFlag = invoke("mdm.supplierBusinessScopeService.externalCallBusinessScopeClassify",
                        MapUtil.mapper("supplierId", findBaturuSupplier.get(0).getValue(), "classifyId", item.getProduct().getClassify().getId()));
                if (!wantInvoiceFlag && isExistsPurGroup && scopeCarFlag && excluClassifyFlag && !item.isProductRule()) this.baturuInquireData(item, inquireData, platform);
            });
            data.put("PUR_SPXJDMX", itemArray);
            array.add(data);
        });
        commodityInquiryOrderService.createSynSPXJD(array, servicePlan.getInnerBusinessKey());
        try {
            if (!wantInvoiceFlag && isExistsPurGroup && scopeCarFlag) {
//                invoke("fn.servicePlan.servicePlanToInquire", inquireData);
                // 为巴图鲁获取报价做准备
//                int inquiryDetailsSize = StringUtils.isEmpty(inquireData.get("inquiryDetails"))?0:inquireData.getJSONArray("inquiryDetails").size();
//                invoke("fn.timingOfferService.create",
//                        MapUtil.mapper("origin", servicePlan.getId(), "businessType", servicePlan.getBusinessType(), "dept", MapUtil.mapper("id", servicePlan.getBelongDept().getId(),
//                                "name", servicePlan.getBelongDept().getName()), "partsQty", inquiryDetailsSize));
            }
        } catch (Exception e) {
            outboxSubscriberService.commonSendRequest("local:ServicePlanceService.baturuFailOutbox", "push_baturu_fail_" + servicePlan.getId(), inquireData);
        }
        //三头六臂询价
        /*List<String> dept = SpringManager.getBean(PurchasingGroupRepository.class).accordingPurchasingGroupGetDeptId("0241");
        if (dept.contains(servicePlan.getBelongDept().getId())) santouliubiService.santouInquireMainData(servicePlan);*/

    }

    @OutboxSubscriber(id="local:ServicePlanceService.baturuFailOutbox", name="服务方案推送报价失败")
    public void baturuFailOutbox(OutboxPayloadWrapper outboxPayloadWrapper) {
        invoke("fn.servicePlan.servicePlanToInquire", JSONObject.parseObject(outboxPayloadWrapper.getPayload()));
    }


    /**
     * 询价需要给一个默认货源状态，yy确定的
     * @return
     */
    public Enumeration findCommotidyHY() {
        try{
            return enumerationRepository.findByTypeAndValue("无货", "supplyStatus");
        }catch (Exception e){
            throw new RuntimeException("请先设置货源状态");
        }
    }


    private void addConfirmParas(ServicePlanItem servicePlanItem, JSONObject quiryJson){
        servicePlanItem.setSupplyChainManagement(servicePlanItem.getSupplyChainManagement()/servicePlanItem.getPriceCostUnitInTax()*quiryJson.getDouble("XYGSCGJ")); //供应链管理费用
        servicePlanItem.setPriceCostUnitExTax(quiryJson.getDoubleValue("XYGSCGJ"));//不含税成本单价
        servicePlanItem.setPriceCostUnitInTax(quiryJson.getDoubleValue("XYGSCGJ"));//含税成本单价
        servicePlanItem.setPlatformPriceCosInTax(quiryJson.getDoubleValue("CGDJ"));//平台成本单价
        servicePlanItem.setInquiryPurchaseUnit(quiryJson.getDoubleValue("CGDJ"));//采购单价
        servicePlanItem.setReferTax(servicePlanItem.getSupplyChainManagement()+quiryJson.getDoubleValue("CGDJ"));
        servicePlanItem.setEstimatedCommission((Double)(SpringManager.getBean(TCService.class).obtainEstimatedCommission(
                servicePlanItem.getProduct().getId(),
                servicePlanItem.getProduct().getClassify().getId(),
                servicePlanItem.getServeType().getId(),
                servicePlanItem.getProduct().getBrand().getId(),
                servicePlanItem.getReferTax(),
                servicePlanItem.getPftPriceUnit(),
                servicePlanItem.getFloorPrice(),
                servicePlanItem.getPriceUnit(),
                quiryJson.getString("COMPANYID"),quiryJson.getString("OPERATION")
        )));
    }

    /**
     * 查询单个数据
     * @param request
     * @return
     */
    public ServicePlan findOne(SimpleRequest request) {
        String id = request.get("id");

        ServicePlan servicePlan = findCarServiceLevel(servicePlanRepository.findOne(id));
        if (servicePlan == null) throw new RuntimeException("服务方案：" + request.get("id") + " 在系统中不存在。");
        return getCurrentTimeData(servicePlan);
    }

    /**
     * 查询单个数据(增加工单跳转途经)
     * @param request
     * @return
     */
    public ServicePlan findOneByTurn(SimpleRequest request) {
        String id = request.get("id");
        if (id==null)return null;
        ServicePlan servicePlan = servicePlanRepository.findOne(id);
        if (!id.contains("FW") && servicePlan==null){
            //工单跳转过来
            MaintenanceOrder maintenanceOrder = maintenanceOrderRepository.findOne(id);
            servicePlan = maintenanceOrder.getServicePlanItem().getServicePlan();
        }
        servicePlan = findCarServiceLevel(servicePlan);
        if (servicePlan == null) throw new RuntimeException("服务方案：" + request.get("id") + " 在系统中不存在。");
        return getCurrentTimeData(servicePlan);
    }

    public ServicePlan getCurrentTimeData(ServicePlan servicePlan) {
        servicePlan = (ServicePlan) insertCommonData(servicePlan);

        checkStock(servicePlan);
//        auditNodeService.insertAuditNodeServiceData(servicePlan);
        return servicePlan;
    }

    private void checkStock(ServicePlan servicePlan) {
        if (servicePlan.getConfirmDate()==null)return;
        //获取要货明细
        List<ProductRequireItem> items = new ArrayList<>();
        productRequireRepository.findAllBySource(servicePlan.getId())
                .stream()
//                .filter(productRequire -> productRequire.getState().equals("create"))
                .map(ProductRequire::getProductRequireItems)
                .forEach(items::addAll);
        Map<String, List<ProductRequireItem>> products = items.stream().collect(groupingBy(productRequireItem -> productRequireItem.getProduct().getId()));

        servicePlan.getServicePlanItems().stream().filter(servicePlanItem -> "10".equals(servicePlanItem.getProduct().getProductGroup().getId()))
                .forEach(servicePlanItem -> {
                    insertRemark(servicePlanItem,"ProductRequire",products.get(servicePlanItem.getProduct().getId()));
                    insertRemark(servicePlanItem,"ProductReceive",productReceiveRepository.findbyServicePlanItem(servicePlanItem.getId()));

                });
    }

    private void insertRemark(ServicePlanItem servicePlanItem,String orderType,List items) {
        Product product = servicePlanItem.getProduct();
        if (!product.getProductGroup().getId().equals("10"))return;
        if ((items == null || items.isEmpty()) && "ProductReceive".equals(orderType)) {
            // 配件没有领用单时跳转控制
            servicePlanItem.setQtyReceiveView(MapUtil.mapper("remark", "", "qty", 0.0, "button", 4, "linkId", new ArrayList<>()));
        }
        if (items==null||items.isEmpty())return;

        // 要货/领用按钮显示
        boolean isRequireView = true;
        JSONObject view = new JSONObject();
        view.put("remark","");  // 备注
        view.put("qty",0.0);  // 数量
        view.put("button",1);  // 显示前端按钮
        view.put("linkId",new ArrayList());  // 跳转页面查询订单号

        for (Object item : items) {
            //要货单明细
            if (item instanceof ProductRequireItem){
                ProductRequireItem requireItem = (ProductRequireItem) item;

                view.put("button",!"create".equals(requireItem.getProductRequire().getState()) ? 2 : 1);
                view.put("qty", ((double)view.get("qty")) + requireItem.getQtyRequire());
                if(!"approve".equals(requireItem.getProductRequire().getState())) view.put("remark","要货单未审核,单号:" + requireItem.getProductRequire().getId() + "<br/>");
                ((List)view.get("linkId")).add(requireItem.getProductRequire().getId());
            }
            if (item instanceof ProductReceiveItem){
                ProductReceiveItem productReceiveItem = (ProductReceiveItem) item;
                isRequireView = false;

                view.put("button","create".equals(productReceiveItem.getProductReceive().getState()) ? 1 : 2);
                view.put("qty", ((double)view.get("qty")) + (productReceiveItem.getQtyReceive()-productReceiveItem.getQtyReturned()+productReceiveItem.getQtyToSales()));
                if("create".equals(productReceiveItem.getProductReceive().getState())) view.put("remark","领用单未审核,单号:" + productReceiveItem.getProductReceive().getId() + "<br/>");
                ((List)view.get("linkId")).add(productReceiveItem.getProductReceive().getId());
            }
        }

        if (((List)view.get("linkId")).size() > 1) view.put("button", 3);

        if (isRequireView){
            servicePlanItem.setRequireView(view);
        }else{
            if (view.getDouble("qty") == 0) view.put("button",4); // 配件未领用
            servicePlanItem.setQtyReceiveView(view);
        }

    }

    /**
     * 查询车辆服务等级
     * @param servicePlan
     * @return
     */
    public ServicePlan findCarServiceLevel(ServicePlan servicePlan){
        if (servicePlan==null)return servicePlan;
        if (StringUtils.isEmpty(servicePlan.getCustomerCar().get("carServiceLevel"))&&!servicePlan.getCustomerCar().get("carServiceLevel").equals("")) return servicePlan;

        JSONObject carServiceLevelJson = SpringManager.getBean(FnApiService.class).getCarServiceLevel((String)servicePlan.getCustomerCar().get("jekunModelCode"));
        String carBase= carServiceLevelJson.getString("CarServiceLevelName");
        String carModel= carServiceLevelJson.getString("carModel");
        if (carBase != null && !carBase.equals("")) {
            servicePlan.setCarServiceLevel("[" + carBase + "]");
        }else {
            servicePlan.addErrorMsg("["+carModel+"]该车型未定义车型服务等级，请联系客服中心对接人补齐");
        }
        return servicePlan;
    }

    /**
     * 查询询价信息总入口
     * @param simpleRequest
     * @return
     */
    public JSONObject qryXJDetail(SimpleRequest simpleRequest){
        JSONObject json = simpleRequest.getJO();
        JSONObject resultObject = new JSONObject();
        String id = json.getString("id");
        if(StringUtils.isEmpty(id)) return null;
        ServicePlan servicePlan = servicePlanRepository.findOne(id);
        if(Optional.ofNullable(servicePlan).isPresent()){
            resultObject = qryXJDetailForFW(simpleRequest);
        }else{
            LossQuotation lossQuotation = lossQuotationRepository.findOne(id);
            if (Optional.ofNullable(lossQuotation).isPresent())
            resultObject = SpringManager.getBean(LossQuotationService.class).qryXJDetailForDS(simpleRequest);
        }
        return resultObject;
    }


    public JSONObject qryXJDetailForFW(SimpleRequest simpleRequest){
        JSONObject json = simpleRequest.getJO();
        String id = json.getString("id");
        if(id == null || "".equals(id.trim())) return null;
        ServicePlan servicePlan = servicePlanRepository.findOne(id);
        if(servicePlan == null) throw new RuntimeException("miss：cannot find servicePlan ,id:" + id);

        //车辆信息
        FnCustomerExpand fnCustomerExpand = servicePlan.getFnCustomerExpand();
        //根据配件名称分组，询价过的商品
        Map<String, List<ServicePlanItem>> map = servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem-> servicePlanItem.getOldInquiryNumber() != null && !"".equals(servicePlanItem.getOldInquiryNumber().trim()))
                .collect(Collectors.groupingBy(servicePlanItem -> servicePlanItem.getProduct().getCategory().getId()));
        //构建json
        JSONObject reJson = new JSONObject();
        reJson.put("carLicense",fnCustomerExpand == null ? null : fnCustomerExpand.getCarLicense());
        reJson.put("modelName",fnCustomerExpand == null ? null : fnCustomerExpand.getCarModelLabel());

        JSONArray array = new JSONArray();
        //获取需要调用内协
        LossQuotationService lossQuotationService = SpringManager.getBean(LossQuotationService.class);
        map.forEach((categoryId,servicePlanItems)->{
            JSONObject tempJson = new JSONObject();
            tempJson.put("categoryName",servicePlanItems.stream().findFirst().get().getCategory().getName());
            tempJson.put("categoryId",servicePlanItems.stream().findFirst().get().getCategory().getId());
            tempJson.put("inquryDetail","");
            tempJson.put("item",servicePlanItems.stream().map(servicePlanItem->{
                JSONObject tempJson1 = new JSONObject();
                tempJson1.put("name",servicePlanItem.getProduct().getName());
                tempJson1.put("qtyLimit",servicePlanItem.getQualityWarranty());
                tempJson1.put("qtyWay",servicePlanItem.getQualityMileage());
                tempJson1.put("goodsState",servicePlanItem.getInquiryGooodsState());
                tempJson1.put("goodsGetDetail","");
                tempJson1.put("remark",servicePlanItem.getRemarks());
                tempJson1.put("price",servicePlanItem.getPftPriceUnit());
                tempJson1.put("cusRemark","");
                tempJson1.put("serviceplanitemId",servicePlanItem.getId());
                tempJson1.put("id",servicePlanItem.getProduct().getId());
                tempJson1.put("inquirySelectFlag",servicePlanItem.getInquirySelectFlag());

                //该商品对应的询价信息
                JSONObject condition = new JSONObject();
                condition.put("XJDH",servicePlanItem.getOldInquiryNumber());
                condition.put("SPID",servicePlanItem.getProduct().getId());
                lossQuotationService.getOldInquiryInfo(condition,tempJson1);
                return tempJson1;
            }).collect(Collectors.toCollection(JSONArray::new)));
            array.add(tempJson);
        });
        lossQuotationService.handleSupplierCode(array);
        reJson.put("item",array);
        return reJson;
    }

    /**
     *
     * @param innerFrom
     * @param innerType
     * @return
     */
    public List<ServicePlan> findServicePlanByInnerSourceFromAndInnerSourceFromType(String innerFrom,String innerType){
        List<ServicePlan> list = servicePlanRepository
                .findServicePlanByInnerSourceFromAndInnerSourceFromType(innerFrom,innerType);
        if(list == null) list = new ArrayList<ServicePlan>();
        return list;
    }

    public Page<Object[]> findAllForInquiry(SimpleRequest request) {
        return findAllByNatureSql(request, (param) -> servicePlanDao.queryForInquiry(param));
    }

    /***
     * 查询可领用的服务方案
     */
    public Page<Object[]> findAllForReceive(SimpleRequest request){
        return findAllByNatureSql(request, (param) -> servicePlanDao.queryForReceive(param));
    }

    private Page<Object[]> findAllByNatureSql(SimpleRequest request, Function<JSONObject, JSONArray> func) {
        JSONObject param = new JSONObject();
        List<Map> fields = request.get("condition");
        String postId = request.getPostId();
        if(postId == null) throw new RuntimeException("未找到当前人员的登录信息，请重新登录！");
        Post post = postRepository.findOne(postId);
        if(post.getDept() == null) throw new RuntimeException("未找到当前登录角色所属部门，请切换角色！");
        param.put("DEPT",post.getDept().getId());
        fields.stream().forEach(field -> {
            if (field.get("field").toString().equals("ID")) {
                param.put("ID", field.get("value").toString());
            }
            if (field.get("field").toString().equals("CAR_LICENSE")) {
                param.put("CAR_LICENSE", field.get("value").toString());
            }
        });

        // 获取数据
        JSONArray array = func.apply(param);

        Pageable pageable = PageRequest.of(request.get("page"), request.get("size"));
        int fromIndex = pageable.getPageSize()*pageable.getPageNumber();
        int toIndex = pageable.getPageSize()*(pageable.getPageNumber()+1);
        if(toIndex > array.size()) toIndex = array.size();
        JSONArray current = new JSONArray(array.subList(fromIndex,toIndex));
        PageImpl page = new PageImpl<>(current, pageable, array.size());
        return page;
    }

    /***
     * 获取领用明细
     */
    public List<Object> findAllItemForReceive(SimpleRequest request) {

        List<ServicePlanItem> items = servicePlanItemRepository.findServicePlanItemsForPDA(
                request.get("id"), request.get("locationId"));
        return items.stream().map(item -> {
            Map m = new HashMap();
            m.put("product", item.getProduct());
            m.put("uom", item.getUom());

            // 获取可用数
            ProductAccountService productAccountService = SpringManager.getBean(ProductAccountService.class);
            Map map = productAccountService.getUomUsableQty(item.getLocation(), item.getProduct(), item.getUom(), item.getServicePlan().getCompany());
            if (map.isEmpty()) return 0.00;
            m.put("marketableQty", map.isEmpty() ? 0.00 : map.get("marketableQty"));

            m.put("qtyReceived", item.getQtyReceive()); // 已领用数量
            m.put("qtySale", item.getSaleQty() - item.getQtyEnd()); // 销售数量
            m.put("servicePlanItem", item); // 服务方案明细
            return m;
        }).collect(Collectors.toList());
    }



    /**
     * app生成方案
     * 商品订单
     */
    public ServicePlan servicePlanCreate(SimpleRequest simpleRequest) {
        JSONObject jo = simpleRequest.getJO();
        ServicePlan servicePlan = simpleRequest.getO(ServicePlan.class);
        JSONObject customerCar = jo.getJSONObject("customerCar");
        JSONObject customerInfo = jo.getJSONObject("customerInfo");
        servicePlan.setCarLiscence(customerCar.getString("carLicense")); //目的为了锁车牌
        //根据来源，判断app是否调用两次
        ServicePlan oldPlan = checkRepetition(servicePlan);
        if (oldPlan != null) return oldPlan;
        String license = "fn.serviceApp.servicePlanCreate" + customerCar.getString("carLicense") + servicePlan.getSourceFrom();
        boolean isPlatformOrder = servicePlan.getChannel() == null || !PLATFORM_OUT_ORDER.contains(servicePlan.getChannel().getName() );
        try {
            //运行时防重控制
            if (!distributedLock.lock(license, 1000 * 20)) {
                throw new RuntimeException("请勿重复点击");
            }

            if (servicePlan.getInsuranceDiscounts() != null)
                servicePlan.setSourceBusinessTypeName(servicePlan.getSourceBusinessTypeName() + "(车险优惠)");
            servicePlan.setFnCustomerExpand(
                    findFnCustomerExpandAndSave(servicePlan.getBelongDept(), customerInfo, customerCar)
            );
            //用到的参数
            Dept belongDept = servicePlan.getBelongDept();
            FnCustomerExpand fnCustomerExpand = servicePlan.getFnCustomerExpand();
            CooperateType cooperateType = servicePlan.getCooperationType();

            User user = SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id", servicePlan.getOperator1().getId())).stream().findFirst().orElse(null);
            servicePlan.setUserId(user == null ? null : String.valueOf(user.getId()));
            servicePlan.setCreator(servicePlan.getOperator1().getId());

            servicePlan.insertGetCarInfoForMap(carInformation(customerCar, belongDept));
            //处理明细数据取值
            servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
                //2022年8月23日 要求销售单价取售价
                servicePlanItem.setPrimaryPriceUnit(servicePlanItem.getPftPriceUnit());
                servicePlanItem.setPrimaryPriceUnitShow(servicePlanItem.getPrimaryPriceUnit());
                servicePlanItem.setPriceUnit(servicePlanItem.getPftPriceUnit());
                //设置计量单位
                try {
                    servicePlanItem.setUom(servicePlanItem.getProduct().getUom());
                } catch (Exception e) {
                    throw new RuntimeException("计量单位获取错误，商品编码:" + servicePlanItem.getProduct().getId() + ",计量单位" + jo.getString("uomName"));
                }

                boolean productRule = ((List) this.invoke("cm.consignmentRule.findAllByCategoryAndProvinceAndCity",
                        MapUtil.mapper("deptId", belongDept.getId(),
                                "categoryId", servicePlanItem.getProduct().getCategory().getId(), "brandId", servicePlanItem.getProduct().getBrand().getId())
                )).size() != 0;
                servicePlanItem.setProductRule(productRule);
                Location location = SpringManager.getBean(LocationService.class).findLocationByDept(belongDept, productRule);
                if (location == null) throw new RuntimeException("请定义该门店对应仓库:" + belongDept.getName());
                servicePlanItem.setLocation(location);

                //获取质保信息
                Map map = this.invoke("fn.fnCommunalService.qryQualityInfo", MapUtil.mapper("SPID", servicePlanItem.getProduct().getId(), "PLID", servicePlanItem.getProduct().getClassify().getId(), "PPID", servicePlanItem.getProduct().getBrand().getId()));
                JSONObject qryQualityInfo = map == null ? null : new JSONObject(map);
                if (qryQualityInfo != null) {
                    servicePlanItem.setQualityMileage(qryQualityInfo.getString("qualityMileage"));
                    servicePlanItem.setQualityWarranty(qryQualityInfo.getString("qualityWarranty"));
                }
                //平台信息
                servicePlanItem.setPlatform(SpringManager.getBean(FnCommunalService.class).getPlatform(false, true, belongDept, servicePlanItem.getProduct()));
            });
            String vendorCode = servicePlan.getFnCustomerExpand().getVendorCode();
            String carLicense = servicePlan.getFnCustomerExpand().getCarLicense();
            Object mobile = servicePlan.getCustomer().get("mobile");
            String deptId = servicePlan.getBelongDept().getId();

            if (isPlatformOrder) {
                JSONArray jgArray = serviceToForeign.getXS51(
                        servicePlan.getServicePlanItems().stream().map(servicePlanItem -> {
                            return MapUtil.mapper(
                                    "uniqueIdentify", servicePlanItem.getProduct().getId(),
                                    "SPMC", servicePlanItem.getProduct().getName(),
                                    "MDID", belongDept.getOrigin(),
                                    "PLID", servicePlanItem.getProduct().getClassify().getId(),
                                    "SPID", servicePlanItem.getProduct().getId(),
                                    "HZLXID", cooperateType == null ? null : cooperateType.getId(),
                                    "PPID", servicePlanItem.getProduct().getBrand().getId(),   //品牌找品质
                                    "PZID", servicePlanItem.getProduct().getBrand().getQuality() == null ? null : servicePlanItem.getProduct().getBrand().getQuality().getCode(),
                                    "XSZZID", belongDept.getCompany().getId(),
                                    "GSID", belongDept.getCompany().getId(),
                                    "FNKHID", fnCustomerExpand.getUnitClientId(),
                                    "CLFWDJID", ((CarServiceLevel) (SpringManager.getBean(CarServiceLevelService.class).findByCarConfigurationId(fnCustomerExpand.getJekunModelCode()))).getId(),
                                    //"MDLXID", belongDept.getDeptType().getId(),
                                    "FNVIPJBID", fnCustomerExpand.getCustomerLevelId(),
                                    "FNVIPSFID", fnCustomerExpand.getUserRoleId(),
                                    "CGZZID", servicePlanItem.getPlatform().getId(),
                                    "JLDW", servicePlanItem.getUom().getName(),
                                    "JLDWID", servicePlanItem.getUom().getId(),
                                    "JRS", vendorCode,
                                    "CPHM", carLicense,
                                    "SJHM", mobile,
                                    "XSMD", deptId,
                                    "YYMS", belongDept.getCompany().getParty().getCorporate().getOperation().getCode(),
                                    "NYYMS", belongDept.getCompany().getParty().getCorporate().getOperation().getId(),
                                    "CPHM", fnCustomerExpand.getCarLicense(),
                                    "SYGSID", servicePlanItem.getPlatform().getId(),
                                    "SQID", SpringManager.getBean(StoreService.class).findBusinessCircleByDept(belongDept).getId(),
                                    "XYGSID", belongDept.getCompany().getId(),
                                    "KYS", 0
                            );
                        }).collect(Collectors.toList()), true
                );

                servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
                    boolean flag = true;
                    //设置价格
                    for (int i = 0; i < jgArray.size(); i++) {
                        JSONObject item = jgArray.getJSONObject(i);
                        if (item.getString("uniqueIdentify").equals(servicePlanItem.getProduct().getId())) {
                            throwProductPriceListException(jgArray, servicePlanItem, item);

                            servicePlanItem.setManagementFeeRate(item.getDouble("managementFeeRate"));
                            servicePlanItem.setFloorPrice(item.getDouble("floorPrice"));
                            servicePlanItem.setClerkPriceLimit(item.getDouble("clerkPriceLimit"));
                            servicePlanItem.setShopOwnerPriceLimit(item.getDouble("shopOwnerPriceLimit"));
                            servicePlanItem.setCsoPriceLimit(item.getDouble("csoPriceLimit"));
                            servicePlanItem.setDiscountRate(item.getDouble("discountRate"));
                            servicePlanItem.setPriceSource(item.getString("priceSource"));
                            servicePlanItem.setPriceCostUnitInTax(item.getDouble("priceCostUnitInTax"));
                            servicePlanItem.setPriceCostUnitExTax(item.getDouble("priceCostUnitExTax"));
                            servicePlanItem.setPlatformPriceCosInTax(item.getDouble("platformPriceCosInTax"));
                            servicePlanItem.setFloorPrice(item.getDouble("floorPrice"));
                            servicePlanItem.setPriceSource(item.getString("priceSource"));
                            servicePlanItem.setSupplyChainManagement(item.getDouble("supplyChainManagement") == null ? 0 : item.getDouble("supplyChainManagement"));
                            servicePlanItem.setReferTax(item.getDouble("referTax") == null ? 0 : item.getDouble("referTax"));
                            flag = false;
                        }
                    }
                    if (flag) throw new RuntimeException("商品未定义价格，请联系定义：" + servicePlanItem.getProduct().getName());
                });
            }


            //新增
            servicePlan.setState("create");
            getPlanDept(servicePlan, getSession(simpleRequest) == null ? null : getSession(simpleRequest).getBranchId());
            //提交
            submitProcess(simpleRequest, servicePlan);
            //确认
            confirmProcess(simpleRequest, servicePlan);
            //通知APP
            confirmToApp(servicePlan);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        } finally {
            distributedLock.unlock(license);
        }
        return servicePlan;
    }

    private void submitProcess(SimpleRequest simpleRequest, ServicePlan servicePlan) {
        servicePlan.setState("submission");
        //设置相关信息
        setInformationDetail(simpleRequest, servicePlan);

        //提交对明细进行一个修改
        changeSubmissionItem(servicePlan);

        //生成来源门店的方案
        createSourceFromPlan(servicePlan);
    }

    public ServicePlan appCreateCallback(SimpleRequest request){
        ServicePlan servicePlan = request.getO(ServicePlan.class);
        //根据来源，判断app是否调用两次
        ServicePlan oldPlan = checkRepetition(servicePlan);
        return oldPlan;
    }

    private ServicePlan checkRepetition(ServicePlan servicePlan) {

        List<ServicePlan> servicePlans =
                servicePlanRepository.findAll(JpaDsl.toCriteriaByEq("sourceFrom", servicePlan.getSourceFrom(), "terminationDate", null));
        if (servicePlans.size() != 0) { //21.04.22 更改，非上线。查到生成过的单据直接作返回操作给他们
            return servicePlans.stream().findFirst().get();
        }
        return null;
    }

    /**
     * 富登/卡内签收逻辑
     * @param re
     * @return
     */
    public Object shipmentsOrReceipt(SimpleRequest re){
        JSONObject jo = re.getJO();
        MaintenanceOrder maintenanceOrder = findMaintenanceOrderFittingsByFD(jo);

        ServicePlan servicePlan = maintenanceOrder.getServicePlanItem().getServicePlan();
        Product product = maintenanceOrder.getProduct();

        if (jo.containsKey("factoryFittingsTime")){
            addServicePlanLogger(servicePlan,servicePlan.getChannel().getName()+"已发货","商品:["+product.getId()+"]"+ product.getName()+" 已发货!");
            //发货逻辑
            shipments(maintenanceOrder,jo.getDate("factoryFittingsTime"));
        }
        if (jo.containsKey("receiptedTime")) {
            addServicePlanLogger(servicePlan,servicePlan.getChannel().getName()+"已签收","商品:["+product.getId()+"]"+ product.getName()+" 已签收!");
            //签收逻辑
            autoOutByFD(receipt(maintenanceOrder,jo.getDate("receiptedTime")));

        }
        return MapUtil.mapper("succeed","true");
    }

    private MaintenanceOrder findMaintenanceOrderFittingsByFD(JSONObject jo){
        ServicePlan servicePlan = servicePlanRepository.findOne(jo.getString("id"));
        if (servicePlan == null)  throw new RuntimeException("该服务方案不存在！");
        if (servicePlan.getChannel() == null ||!PLATFORM_OUT_ORDER.contains(servicePlan.getChannel().getName())) throw new RuntimeException("该服务方案不是对应渠道！");
        ServicePlanItem servicePlanItem = servicePlan.getServicePlanItems().stream().filter(item -> PLATFORM_OUT_ORDER.contains(item.getProduct().getBrand().getName())).findFirst().orElse(null);
        return maintenanceOrderRepository.findByServicePlanItemAndBusinessType(servicePlanItem, "common");
    }

    private MaintenanceOrder shipments(MaintenanceOrder maintenanceOrder,Date factoryFittingsTime){
        if(factoryFittingsTime == null) throw new RuntimeException("入参缺少发货时间！");
        maintenanceOrder.setFactoryFittingsTime(factoryFittingsTime);
        return maintenanceOrderRepository.save(maintenanceOrder);
    }

    private MaintenanceOrder receipt(MaintenanceOrder maintenanceOrder,Date receiptedTime){
        if(receiptedTime == null) throw new RuntimeException("入参缺少签收时间！");
        maintenanceOrder.setReceiptedTime(receiptedTime);
        return maintenanceOrderRepository.save(maintenanceOrder);
    }

    private void autoOutByFD(MaintenanceOrder maintenanceOrder){
        ServicePlan servicePlan = findServicePlanByMaintenanceOrder(maintenanceOrder);
        pushOutboxMsgByFD(servicePlan); // 异步自动外协
    }

    /**
     * 修改工单工厂配货时间
     * @param re
     * @return
     */
    private MaintenanceOrder changeMaintenanceOrderByFactoryFittingsTime(SimpleRequest re){
        MaintenanceOrder origin = re.getO(MaintenanceOrder.class);
        MaintenanceOrder maintenanceOrder = maintenanceOrderRepository.findOne(origin.getId());
        if (maintenanceOrder == null) throw new RuntimeException("没有找到该工单!");
        if (maintenanceOrder.getFactoryFittingsTime() != null) throw new RuntimeException("该工单已经存在工厂配货时间！");
        if (origin.getFactoryFittingsTime() == null) throw new RuntimeException("入参缺少工厂配货时间！");
        maintenanceOrder.setFactoryFittingsTime(origin.getFactoryFittingsTime());
        return maintenanceOrderRepository.save(maintenanceOrder);
    }

    private ServicePlan findServicePlanByMaintenanceOrder(MaintenanceOrder maintenanceOrder){
        String id = maintenanceOrder.getServicePlanItem().getServicePlan().getId();
        ServicePlan servicePlan = servicePlanRepository.findOne(id);
        if (servicePlan == null) throw new RuntimeException("没有找到该服务方案单！");
        return servicePlan;
    }

    private void pushOutboxMsgByFD(ServicePlan servicePlan) {
        // 推送消息
        OutboxPayloadWrapper wrapper = new OutboxPayloadWrapper();
        wrapper.setSubscriber("servicePlanceService.outboxMsgByFD");        // 调用的 esb 方法
        wrapper.setAggregateId(servicePlan.getId());                        // 单号
        wrapper.setPayload(servicePlan.getId());                            // 传入的消息体
        SpringManager.getBean(OutboxEventService.class).sendSaveEvent(wrapper);
    }

    @OutboxSubscriber(id="servicePlanceService.outboxMsgByFD", name="富登/卡内自动外协")
    public void outboxMsgByFD(OutboxPayloadWrapper wrapper){
        String servicePlanId = wrapper.getPayload();
        ServicePlan servicePlan = servicePlanRepository.findOne(servicePlanId);
        servicePlanByFD(servicePlan);
    }

    /**
     * 自动转外协、外协派工、外协完工
     * @param servicePlan
     */
    private void servicePlanByFD(ServicePlan servicePlan){
        if (!isFD(servicePlan)) return;
        // 判断是否已经转外协
        if (haveOutMaintenanceOrder(servicePlan)) return;
        // 自动外协
        if (!isOut(servicePlan)) outsourcing(servicePlan);
        // 自动外协派工
        outsourcingDispatch(servicePlan);
        // 自动外协完工
        autoOutFinish(servicePlan);
    }

    /**
     * 判断是否该服务方案单是否存在外协工单
     * @param servicePlan
     * @return
     */
    private boolean haveOutMaintenanceOrder(ServicePlan servicePlan){
        List<String> list = servicePlan.getServicePlanItems().stream().filter(servicePlanItem -> PLATFORM_OUT_ORDER.contains(servicePlanItem.getProduct().getBrand().getName())).map(servicePlanItem -> servicePlanItem.getId()).collect(Collectors.toList());
        List<MaintenanceOrder> maintenanceOrders = maintenanceOrderRepository.findMaintenanceOrderByOut("out",list);
        return maintenanceOrders.size() > 0;
    }

    /**
     * 判断是否该服务方案单是否存在已经转外协
     * @param servicePlan
     * @return
     */
    private boolean isOut(ServicePlan servicePlan){
        List<String> list = servicePlan.getServicePlanItems().stream().filter(servicePlanItem -> PLATFORM_OUT_ORDER.contains(servicePlanItem.getProduct().getBrand().getName())).map(servicePlanItem -> servicePlanItem.getId()).collect(Collectors.toList());
        List<MaintenanceOrder> maintenanceOrders = maintenanceOrderRepository.findAll(JpaDsl.toCriteria("servicePlanItem.id", "in", list,
                "state", "EQ", MaintenanceOrder.CONST_TABLE_STATE_OUTER));
        maintenanceOrders = maintenanceOrders.stream().filter(maintenanceOrder -> !Objects.isNull(maintenanceOrder.getReceiptedTime())).collect(Collectors.toList());
        return maintenanceOrders.size() > 0;
    }

    /**
     * 平台外订单外协
     * @param servicePlan
     */
    private void outsourcing(ServicePlan servicePlan){
        // 查找配件的服务方案明细的工单
        List<String> servicePlanItemIds = servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem -> LogicalUtil.in(servicePlanItem.getProduct().getBrand().getName(),PLATFORM_OUT_ORDER.get(0))
                        ||servicePlanItem.isNeedAutoTransitionAssistTypeForKN())
                .map(ServicePlanItem::getId).collect(Collectors.toList());
        if(servicePlanItemIds.size() <= 0) throw new RuntimeException("没有对应品牌配件商品！");
        List<MaintenanceOrder> maintenanceOrders = maintenanceOrderRepository.findMaintenanceOrderByServicePlanItemIds(servicePlanItemIds);
        // 编辑工单数据
        maintenanceOrders.stream().forEach(maintenanceOrder -> {
            maintenanceOrder.setOutAssistType("inPlatform");
            maintenanceOrder.setSelected(true);
        });
        addServicePlanLogger(servicePlan,"转外协",servicePlan.getChannel().getName()+"自动转外协",systemOperator()); // 记录日志
        // 转外协
        this.invoke("fn.maintenance.toOutForInvoke",JSON.toJSONString(MapUtil.mapper("maintenanceOrders",maintenanceOrders,
                                                                                    "createLogger",false,
                                                                                    "loggerRemark",servicePlan.getChannel().getName()+"自动转外协")));
    }

    private String systemOperator() {
        User system = SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id", "system")).stream().findFirst().orElse(null);
        return Objects.isNull(system) ? "0" : system.getId() + "";
    }

    private void outsourcingDispatch(ServicePlan origin){
        ServicePlan servicePlan = servicePlanRepository.findOne(origin.getId());

        // 判断采购合同的合作方式是否为代销
        // checkContract(servicePlan);
        // 外协派工
        invokeMaintenanceDispatch(servicePlan);
    }

    private void invokeMaintenanceDispatch(ServicePlan servicePlan){
        // 获取派工审核所需入参
        List<MaintenanceOrder> maintenanceOrders = getMaintenanceOrdersByFD(servicePlan);
        addServicePlanLogger(servicePlan,"外协派工",servicePlan.getChannel().getName()+"自动派工",systemOperator()); // 记录日志
        // 外协派工
        this.invoke("fn.maintenance.dispach",JSON.toJSONString(MapUtil.mapper("maintenanceOrders",maintenanceOrders,
                "createLogger",false,
                "loggerRemark",servicePlan.getChannel().getName()+"自动派工")));
    }

    /**
     * 外协自动完工（富登/卡内）
     * @param servicePlan
     */
    private void autoOutFinish(ServicePlan servicePlan){
//        addServicePlanLogger(servicePlan,"外协工单完成","富登脚垫自动完工","0"); // 记录日志
        List<String> list = servicePlan.getServicePlanItems().stream().map(ServicePlanItem::getId).collect(Collectors.toList());
        List<MaintenanceOrder> maintenanceOrders = maintenanceOrderRepository.findOutMaintenanceOrder("create",list);
        maintenanceOrders.stream().forEach(maintenanceOrder -> {
            // 平台外单据自动外协的完成人为系统
            maintenanceOrder.setFinishUid(SpringManager.getBean(PartyRoleRepository.class).findOne("system"));
        });
        this.invoke("fn.maintenance.outFinish",JSON.toJSONString(MapUtil.mapper("maintenanceOrders",maintenanceOrders)));
    }

    private List<MaintenanceOrder> getMaintenanceOrdersByFD(ServicePlan servicePlan){
        List<String> list = servicePlan.getServicePlanItems().stream()
                                       .filter(servicePlanItem -> LogicalUtil.in(servicePlanItem.getProduct().getBrand().getName(),PLATFORM_OUT_ORDER.get(0))
                                                   ||servicePlanItem.isNeedAutoTransitionAssistTypeForKN())
                                       .map(ServicePlanItem::getId).collect(Collectors.toList());
        List<MaintenanceOrder> maintenanceOrders = maintenanceOrderRepository.findOutDiapatcherOrder("waitDispatch",list);
        return maintenanceOrders.stream().map(item -> {
            return writePlatformOutOrderMaintenanceDetail(servicePlan, item);
        }).collect(Collectors.toList());
    }

    /**
     * 卡内/富登 修改外协工单明细
     * @param servicePlan
     * @param item
     * @return
     */
    private MaintenanceOrder writePlatformOutOrderMaintenanceDetail(ServicePlan servicePlan, MaintenanceOrder item) {
        switch (servicePlan.getChannel().getName()) {
            case "富登":
                writeFDOrderMaintenanceDetail(servicePlan, item);
                break;
            case"师人订制":
                writePrivateMakeOrderMaintenanceDetail(servicePlan,item);
                break;
                default:
                    throw new RuntimeException("未设置的渠道来源");
        }

        // 勾选工单选项
        item.setSelected(true);
        return item;
    }
    private void writePrivateMakeOrderMaintenanceDetail(ServicePlan servicePlan, MaintenanceOrder item) {
        ServicePlanItem servicePlanItem = item.getServicePlanItem();
        item.setPlatformPriceCosExTax(servicePlanItem.getReferTax());
        item.setPlatformPriceCosInTaxTemp(servicePlanItem.getReferTax());
        item.setPlatformPurchaseCost(servicePlanItem.getPlatformPurchaseCost());
        item.setCommissionAmount(servicePlanItem.getCommissionAmount());
        item.setTaxRate(0.0);
        item.setSaleChannel(servicePlanItem.getServicePlan().getChannel());
        item.setWorkType(null);
        item.setOutAssistTypeConfirm(true);
        item.setReachDate(null);
        item.setDispatchUid(SpringManager.getBean(PartyRoleRepository.class).findOne("system"));
        //scm.contract.findAllBySupplierOrCooperation
        List<Contract> contracts = new ArrayList<>();
        // 判断是否查询采购合同
        boolean wantInvoice = servicePlan.getCompany().getParty().getCorporate().isWantInvoice();
        if (wantInvoice) {
            contracts = contractRepository.findByPartnerAndCooperation(servicePlanItem.getSupplier(),FD_COOPERATION_ID,
                    "Contract.contractType.supplier","1001");   // 采购合同
        }else{
            contracts = contractRepository.findByPartnerAndCooperation(servicePlanItem.getSupplier(),FD_COOPERATION_ID,
                    "Contract.contractType.platform","1007");   // 平台供应服务协议
        }
        item.setContract(contracts.get(0));

    }
    private void writeFDOrderMaintenanceDetail(ServicePlan servicePlan, MaintenanceOrder item) {
        ServicePlanItem servicePlanItem = item.getServicePlanItem();
        // 修改工单数据（富登逻辑）
        if(servicePlanItem.getReferTax() != 0){
            item.setPlatformPriceCosExTax(servicePlanItem.getReferTax());
            item.setPlatformPriceCosInTaxTemp(servicePlanItem.getReferTax());
        }else{
            item.setPlatformPriceCosExTax(servicePlanItem.getCrossPriceCost());
            item.setPlatformPriceCosInTaxTemp(servicePlanItem.getCrossPriceCost());
        }
        item.setTaxRate(0.0);
        item.setSaleChannel(servicePlanItem.getServicePlan().getChannel());
        item.setCommissionAmount(servicePlanItem.getCommissionAmount());
        item.setWorkType(null);
        item.setOutAssistTypeConfirm(true);
        item.setReachDate(null);
        item.setDispatchUid(SpringManager.getBean(PartyRoleRepository.class).findOne("system"));
        List<Contract> contracts = new ArrayList<>();
        // 判断是否查询采购合同
        boolean wantInvoice = servicePlan.getCompany().getParty().getCorporate().isWantInvoice();
        if (wantInvoice) {
            contracts = contractRepository.findByPartnerAndCooperation(servicePlanItem.getSupplier(),FD_COOPERATION_ID,
                    "Contract.contractType.supplier","1001");   // 采购合同
        }else{
            contracts = contractRepository.findByPartnerAndCooperation(servicePlanItem.getSupplier(),FD_COOPERATION_ID,
                    "Contract.contractType.platform","1007");   // 平台供应服务协议
        }
        sentMessageByDingDing(servicePlanItem.getServicePlan(),wantInvoice,contracts);
        item.setContract(contracts.get(0));
    }

    private void sentMessageByDingDing(ServicePlan servicePlan, boolean wantInvoice, List<Contract> contracts){
        String str = wantInvoice ? "采购合同" : "平台供应服务协议";
        String msg = "服务明细【" + servicePlan.getId() + "】无经销的" + str + "，"+servicePlan.getChannel().getName()+"自动派工失败！";
        // 钉钉发送消息
        if(contracts.size() <= 0){
            EventUtil.sendSynEvent(this, "event:dingding.message.publish", MapUtil.mapper(
                    "userList", "0110483500641146019,19436125611103096795,4227391727489213","content", msg
            )); // 钉钉通知资慧
            throw new RuntimeException(msg);
        }
    }

    private void checkContract(ServicePlan servicePlan){
        servicePlan.getServicePlanItems().stream().filter(item -> item.getProduct().getBrand().getName().equals("富登")).forEach( item -> {
            List<Contract> contracts = new ArrayList<>();
            if (servicePlan.getCompany().getParty().getCorporate().isWantInvoice()) {
                // 采购合同
                contracts = contractRepository.findByPartnerAndCooperation(item.getSupplier(),FD_COOPERATION_ID,
                        "Contract.contractType.supplier","1001");
            }else{
                // 平台供应服务协议
                contracts = contractRepository.findByPartnerAndCooperation(item.getSupplier(),FD_COOPERATION_ID,
                        "Contract.contractType.platform","1007");
            }
            if(contracts.size() <= 0){
                // 钉钉发送消息
                EventUtil.sendSynEvent(this, "event:dingding.message.publish", MapUtil.mapper(
                        "userList", "0110483500641146019",
                        "content", "服务明细【" + item.getId() + "】的合作方式不为经销，富登自动派工失败！"
                ));
                throw new RuntimeException("服务明细【" + item.getId() + "】的合作方式不为经销，派工失败！");
            }
        });
    }

    private Map getRequestByDispach(ServicePlan servicePlan){
        SimpleRequest simpleRequest = new SimpleRequest();
        JSONObject jo = new JSONObject();
        jo.put("SERVICE_PLAN_ID",servicePlan.getId());
        jo.put("STATE","未派工");
        return this.invoke("fn.maintenance.findDispachOrder",simpleRequest);
    }

    /**
     * 执行外协前的入参准备
     * @param id
     * @return
     */
    private Map getRequestBytoOut(String id){
        // {'SERVICE_PLAN_ID':model.id,'operateState':'toOut'}
        JSONObject jo = new JSONObject();
        jo.put("SERVICE_PLAN_ID",id);
        jo.put("operateState","toOut");
        SimpleRequest simpleRequest = new SimpleRequest();
        simpleRequest.setBody(jo.toJSONString());
        return this.invoke("fn.maintenance.findMaintenanceOrderByServicePlan",simpleRequest);
    }

    // 判断服务是否是富登
    private boolean isFD(ServicePlan servicePlan){
        return servicePlan != null
                && PLATFORM_OUT_ORDER.contains(servicePlan.getChannel().getName())
                && "app订单".equals(servicePlan.getSourceBusinessTypeName());
    }

    private void throwProductPriceListException(JSONArray jgArray, ServicePlanItem servicePlanItem, JSONObject item) {
        if(item.getDouble("pftPriceUnit") == 0) {
            StringBuffer sf = new StringBuffer();
            for (int j = 0; j < jgArray.size(); j++) {
                JSONObject jsonObject = jgArray.getJSONObject(j);
                if (jsonObject.getDouble("pftPriceUnit") == 0) {
                    sf.append(j+1+".["+jsonObject.getString("uniqueIdentify")+"]"+jsonObject.getString("PRODUCT_NAME")+"\n");
                }
            }
            throw new RuntimeException("商品未定义价格，请联系定义：" + sf.toString());
        }
    }


    /**
     * app异业
     */
    public Map crossICCreate(SimpleRequest simpleRequest){
        JSONObject jo = simpleRequest.getJO();
        ServicePlan servicePlan = simpleRequest.getO(ServicePlan.class);
        servicePlan.setSaleDept(servicePlan.getBelongDept());
        servicePlan.setServiceDept(servicePlan.getBelongDept());

        JSONObject customerCar = jo.getJSONObject("customerCar");
        JSONObject customerInfo = jo.getJSONObject("customer");
        servicePlan.setCarLiscence(customerCar.getString("carLicense")); //目的为了锁车牌
        servicePlan.setFnCustomerExpand(
                findFnCustomerExpandAndSave(servicePlan.getBelongDept(),customerInfo,customerCar)
        );

        //用到的参数
        Dept belongDept = servicePlan.getBelongDept();
        FnCustomerExpand fnCustomerExpand = servicePlan.getFnCustomerExpand();
        CooperateType cooperateType = servicePlan.getCooperationType();


        //处理明细数据取值
        servicePlan.getServicePlanItems().forEach(servicePlanItem->{
            servicePlanItem.setPrimaryPriceUnitShow(servicePlanItem.getPrimaryPriceUnit());
            servicePlanItem.setPriceUnit(servicePlanItem.getPftPriceUnit());
            //设置计量单位
            try {
                servicePlanItem.setUom(productUomRepository.findAll(
                        JpaDsl.toCriteriaByEq("name",servicePlanItem.getUomName(),"uomCategory.id",servicePlanItem.getProduct().getId())
                ).stream().findFirst().get());
            }catch (Exception e) {
                throw new RuntimeException("计量单位获取错误，商品编码:" +servicePlanItem.getProduct().getId()+",计量单位"+ jo.getString("uomName"));
            }

            boolean productRule = ((List) this.invoke("cm.consignmentRule.findAllByCategoryAndProvinceAndCity",
                    MapUtil.mapper("deptId", belongDept.getId(),
                            "categoryId", servicePlanItem.getProduct().getCategory().getId(), "brandId", servicePlanItem.getProduct().getBrand().getId())
            )).size() != 0;
            servicePlanItem.setProductRule(productRule);
            Location location = SpringManager.getBean(LocationService.class).findLocationByDept(belongDept,productRule);
            if (location==null)throw new RuntimeException("请定义该门店对应仓库:"+ belongDept.getName());
            servicePlanItem.setLocation(location);

            //获取质保信息
            Map map = this.invoke("fn.fnCommunalService.qryQualityInfo",MapUtil.mapper("SPID",servicePlanItem.getProduct().getId(),"PLID",servicePlanItem.getProduct().getClassify().getId(),"PPID",servicePlanItem.getProduct().getBrand().getId()));
            JSONObject qryQualityInfo = map == null ? null : new JSONObject(map);
            if(qryQualityInfo!= null) {
                servicePlanItem.setQualityMileage(qryQualityInfo.getString("qualityMileage"));
                servicePlanItem.setQualityWarranty(qryQualityInfo.getString("qualityWarranty"));
            }
            //平台信息
            servicePlanItem.setPlatform(SpringManager.getBean(FnCommunalService.class).getPlatform(false,true, belongDept,servicePlanItem.getProduct()));
        });
        String vendorCode = servicePlan.getFnCustomerExpand().getVendorCode();
        String carLicense = servicePlan.getFnCustomerExpand().getCarLicense();
        Object mobile = servicePlan.getCustomer().get("mobile");
        String deptId = servicePlan.getBelongDept().getId();
        JSONArray jgArray = serviceToForeign.getXS51(
                servicePlan.getServicePlanItems().stream().map(servicePlanItem->{
                    return MapUtil.mapper(
                            "uniqueIdentify",servicePlanItem.getProduct().getId(),
                            "MDID",belongDept.getOrigin(),
                            "PLID",servicePlanItem.getProduct().getClassify().getId(),
                            "SPID",servicePlanItem.getProduct().getId(),
                            "HZLXID",cooperateType == null ? null : cooperateType.getId(),
                            "PPID",servicePlanItem.getProduct().getBrand().getId(),   //品牌找品质
                            "PZID",servicePlanItem.getProduct().getBrand().getQuality() == null ? null : servicePlanItem.getProduct().getBrand().getQuality().getCode(),
                            "XSZZID",belongDept.getCompany().getId(),
                            "GSID",belongDept.getCompany().getId(),
                            "FNKHID",fnCustomerExpand.getUnitClientId(),
                            "CLFWDJID",((CarServiceLevel)(SpringManager.getBean(CarServiceLevelService.class).findByCarConfigurationId(fnCustomerExpand.getJekunModelCode()))).getId(),
                            //"MDLXID",belongDept.getDeptType().getId(),
                            "FNVIPJBID", fnCustomerExpand.getCustomerLevelId(),
                            "FNVIPSFID",fnCustomerExpand.getUserRoleId(),
                            "CGZZID",servicePlanItem.getPlatform().getId(),
                            "JLDW",servicePlanItem.getUom().getName(),
                            "JLDWID",servicePlanItem.getUom().getId(),
                            "JRS", vendorCode,
                            "CPHM", carLicense,
                            "SJHM", mobile,
                            "XSMD", deptId,
                            "YYMS",belongDept.getCompany().getParty().getCorporate().getOperation().getCode(),
                            "NYYMS",belongDept.getCompany().getParty().getCorporate().getOperation().getId(),
                            "SYGSID",servicePlanItem.getPlatform().getId(),
                            "SQID", SpringManager.getBean(StoreService.class).findBusinessCircleByDept(belongDept).getId(),
                            "XYGSID",belongDept.getCompany().getId(),
                            "KYS",0
                    );
                }).collect(Collectors.toList()),true
        );

        servicePlan.getServicePlanItems().forEach(servicePlanItem->{
            boolean flag = true;
            //设置价格
            for(int i = 0;i<jgArray.size();i++){
                JSONObject item =jgArray.getJSONObject(i);
                if(item.getString("uniqueIdentify").equals(servicePlanItem.getProduct().getId())){
                    if(item.getDouble("pftPriceUnit") == 0) throw new RuntimeException("商品未定义价格，请联系定义：" + servicePlanItem.getProduct().getName());

                    servicePlanItem.setManagementFeeRate(item.getDouble("managementFeeRate"));
                    servicePlanItem.setFloorPrice(item.getDouble("floorPrice"));
                    servicePlanItem.setClerkPriceLimit(item.getDouble("clerkPriceLimit"));
                    servicePlanItem.setShopOwnerPriceLimit(item.getDouble("shopOwnerPriceLimit"));
                    servicePlanItem.setCsoPriceLimit(item.getDouble("csoPriceLimit"));
                    servicePlanItem.setPriceSource(item.getString("priceSource"));
                    servicePlanItem.setDiscountRate(item.getDouble("discountRate"));
                    servicePlanItem.setPriceCostUnitInTax(item.getDouble("priceCostUnitInTax"));
                    servicePlanItem.setPriceCostUnitExTax(item.getDouble("priceCostUnitExTax"));
                    servicePlanItem.setPlatformPriceCosInTax(item.getDouble("platformPriceCosInTax"));
                    servicePlanItem.setFloorPrice(item.getDouble("floorPrice"));
                    servicePlanItem.setPriceSource(item.getString("priceSource"));
                    servicePlanItem.setSupplyChainManagement(item.getDouble("supplyChainManagement") == null ? 0 : item.getDouble("supplyChainManagement") );
                    servicePlanItem.setReferTax(item.getDouble("referTax") == null ? 0 : item.getDouble("referTax") );
                    flag = false;
                }
            }
            if(flag) throw new RuntimeException("商品未定义价格，请联系定义：" + servicePlanItem.getProduct().getName());
        });

        User user =SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id",servicePlan.getOperator1().getId())).stream().findFirst().orElse(null);
        servicePlan.setUserId(user == null ? null : String.valueOf(user.getId()));
        servicePlan.setState("create");

        servicePlan = this.invoke("fn.service.appCreate",servicePlan);
        submitProcess(simpleRequest, servicePlan);
        confirmProcess(simpleRequest,servicePlan);
        //设置异业金额
        //验证传值
        double amount = 0.0;
        double customer = 0.0;
        double customerPrice = jo.getDoubleValue("customerPrice");
        for (ServicePlanItem servicePlanItem : servicePlan.getServicePlanItems()) {
            double saleQty = servicePlanItem.getSaleQty();
            Map crossICPrice = this.invoke("fn.crossIC.calculateCrossIC", MapUtil.mapper(
                    "productID", servicePlanItem.getProduct().getId(), "pftUnit",servicePlanItem.getPftPriceUnit(),"crossID",servicePlanItem.getCrossIC().getId(),"belongID",servicePlan.getBelongDept().getId() ));

            double accountPrice = (Double) crossICPrice.get("deductionUnit");//平台结算门店单价
            double priceCostUnitInTax = (Double)crossICPrice.get("crossPriceCost");//合作成本价
            double customerPrice1 = (Double)crossICPrice.get("crossCustomerPrice");//客户应付单价
            servicePlanItem.setDeductionUnit(accountPrice);//平台结算门店单价
            servicePlanItem.setDeductionAmount(accountPrice*saleQty);//平台结算门店金额
            servicePlanItem.setCrossPriceCost(priceCostUnitInTax);//合作成本价
            servicePlanItem.setCrossCustomerPrice(customerPrice1*saleQty);//客户应付
            servicePlanItem.setCrossAccountPrice(accountPrice);//赋能结算价
            servicePlanItem.setRealPayAmount(customerPrice1*saleQty);
            servicePlanItem.setMatchFlag((Boolean) crossICPrice.get("matchFlag"));
            double priceUnit = servicePlanItem.getPriceUnit();
            double deductionUnit = servicePlanItem.getDeductionUnit()+servicePlanItem.getCrossCustomerPrice();
            if (priceUnit< deductionUnit){
                servicePlanItem.setPftPriceUnit(deductionUnit);
            }else {
                servicePlanItem.setPftPriceUnit(priceUnit);
            }
            servicePlanItem.setSalesAmount(servicePlanItem.getPftPriceUnit()*saleQty);
            servicePlanItem.setDiscountAmount((servicePlanItem.getPftPriceUnit()-accountPrice-customerPrice1)*saleQty);//折扣金额
            amount += (accountPrice+customerPrice1) *saleQty;//合计 门店结算价+客户支付价 *数量 +其他商品
            customer += (customerPrice1 *saleQty);

        }

        BigDecimal b = new BigDecimal(amount);
        BigDecimal a = new BigDecimal(customer);
        amount = b.setScale(2, BigDecimal.ROUND_HALF_EVEN).doubleValue();
        customer = a.setScale(2, BigDecimal.ROUND_HALF_EVEN).doubleValue();
        if (amount!=jo.getDoubleValue("amount"))throw new RuntimeException("平台结算金额错误!erp:"+amount+",app:"+jo.getDoubleValue("amount"));
        if (customer!=customerPrice)throw new RuntimeException("客户应付金额错误!erp:"+customer+",app:"+customerPrice);

        servicePlan = this.invoke("fn.crossIC.crossIC",servicePlan);
        return MapUtil.mapper("id",servicePlan.getId());
    }





    public boolean isToTechnical(ServicePlan servicePlan){
        //TAPDID 1047201 取消技术审核节点
        if(true)return false;
        //存在非快速服务商品
        Set set = servicePlan.getServicePlanItems().stream().filter(servicePlanItem->{
            return servicePlanItem.isServiceState() && !servicePlanItem.getProduct().isFreeServiceValid() && servicePlanItem.getProduct().getClassify().getId().startsWith("S01");
        }).collect(Collectors.toCollection(HashSet::new));
        if(set.size() >0) return true;

        //当服务方案只有配件且配件中有全车件
        set = servicePlan.getServicePlanItems().stream().filter(servicePlanItem->{
            return servicePlanItem.isServiceState() && servicePlanItem.getProduct().getCategory() != null &&
                    (servicePlanItem.getProduct().getClassify().getId().startsWith("M010303")||servicePlanItem.getProduct().getClassify().getId().startsWith("M010304"));
        }).collect(Collectors.toCollection(HashSet::new));
        if(set.size() >0) return true;
        return false;
    }

    /***
     * 刷新当前单据为创建状态（OA专用）
     */
    public ServicePlan refresh(SimpleRequest request) {
        ServicePlan servicePlan = request.getO(ServicePlan.class);
        if(servicePlan.getConfirmDate() == null){
            servicePlan.setState("create");
            servicePlan.setBackTechnicalAuditDate(new Date());
            servicePlan.setBackTechnicalAuditUid(getPerson(request));
            servicePlan.setTechAuditOpinion(request.getJO().getString("wf_comments")); //判断为空
        }
        return servicePlanRepository.saveAndFlush(servicePlan);
    }

    /***
     * 通过前端商品判断是否需要走技术审核
     */
    public Map needTechAudit(SimpleRequest request){

        boolean needTechAudit = false;

        JSONArray array = request.getJA();
        List<Product> products = array.stream().filter(obj -> {
            JSONObject tempJson = (JSONObject) obj;
            return tempJson.get("product") != null;
        }).map(obj -> {
            JSONObject tempJson = (JSONObject) obj;
            return productRepository.findOne(tempJson.getJSONObject("product").getString("id"));
        }).collect(Collectors.toList());

        //存在非快速服务商品
        List<Product> list = products.stream()
                .filter((product)->!product.isFreeServiceValid())
                .collect(Collectors.toCollection(ArrayList::new));
        if(list.size() >0) needTechAudit = true;


        //当服务方案只有配件且配件中有全车件
        list = products.stream()
                .filter((product)->product.getCategory() != null && product.getCategory().getId().startsWith("M0103"))
                .collect(Collectors.toCollection(ArrayList::new));
        if(list.size() >0) needTechAudit = true;

        return MapUtil.mapper("needTechAudit", needTechAudit);
    }

    /***
     * 通过前端价格判断是否需要转技术审核
     * 1. 是否需要价格审批
     * 2. 需要第几级别审批
     * 3. 目前只存在两种审批 店长（级别4） + 老唐（级别123）
     */
    public JSONObject needPriceAudit(ServicePlan servicePlan, SimpleRequest request) {

        Map returnMap;
        Map<String,List<ServicePlanItem>> needPriceAuditMap = new HashMap<>();
        // 默认枚举值
        Enumeration enumeration = enumerationRepository.findOne(
                JpaDsl.toCriteriaByEq(
                        "type.id", "priceLimit",
                        "code", "5"
                )
        ).orElse(null);


//        // 判断价格审批时间是否存在
//        if (servicePlan.getPriceAuditDate() != null) {
//            return new JSONObject(MapUtil.mapper("needPriceAudit", false,"limitLevel", enumeration));
//        }
        List<PriceApprovalReport> lastApproval = auditNodeService.findApprovalProduct(servicePlan);
        Map<String, List<PriceApprovalReport>> approvalMap = lastApproval.stream().collect(groupingBy(PriceApprovalReport::getPlanItemId));
        boolean approvalEmpty = lastApproval.isEmpty();
        // 筛选不服务的商品
        Map<String, List<ServicePlanItem>> groupByLimitLevel = servicePlan.getServicePlanItems().stream()
                .filter(ServicePlanItem::isServiceState)
                .collect(Collectors.groupingBy(
                servicePlanItem -> {
                    double priceApprovalAmt = approvalEmpty ?-1:servicePlanItem.getPriceApprovalAmt();
                    List<PriceApprovalReport> priceApprovalReports = approvalMap.get(servicePlanItem.getId());
                    if (priceApprovalReports!=null&&priceApprovalReports.size()>0){
                        priceApprovalAmt = priceApprovalReports.stream().mapToDouble(PriceApprovalReport::getPftPriceUnit).min().orElse(0.0D);
                    }

                    if (servicePlanItem.isServiceState() && (servicePlanItem.getPftPriceUnit() <= 0 || servicePlanItem.getPriceUnit() <= 0))
                        throw new RuntimeException("存在价格小于等于零的商品：" + servicePlanItem.getProduct().getName());
                    if (priceApprovalAmt > 0 && priceApprovalAmt <= servicePlanItem.getPftPriceUnit()) {
                        return putNeedPriceAuditMap(needPriceAuditMap, servicePlanItem, "5"); //已经审核过 并且审核通过的价格低于等于现价
                    } else if (servicePlanItem.getPftPriceUnit() >= servicePlanItem.getClerkPriceLimit()) {
                        return putNeedPriceAuditMap(needPriceAuditMap, servicePlanItem, "5");  // 店助
                    } else if (servicePlanItem.getPftPriceUnit() >= servicePlanItem.getShopOwnerPriceLimit()) {
                        return putNeedPriceAuditMap(needPriceAuditMap, servicePlanItem, "4");  // 店长
                    } else if (servicePlanItem.getPftPriceUnit() >= servicePlanItem.getCsoPriceLimit()) {
                        return putNeedPriceAuditMap(needPriceAuditMap, servicePlanItem, "3");  // 销售总监
                    } else if (servicePlanItem.getPftPriceUnit() >= servicePlanItem.getFloorPrice()) {
                        return putNeedPriceAuditMap(needPriceAuditMap, servicePlanItem, "2");  // 副总裁
                    } else {
                        return putNeedPriceAuditMap(needPriceAuditMap, servicePlanItem, "1"); // 总裁
                    }
                }));

        // 获取最小的限价级别
        String minLimitLevel = groupByLimitLevel.keySet().stream()
                .min((string1, string2) -> Integer.valueOf(string1).compareTo(Integer.valueOf(string2))).get();

//        int i=1/0;
        // 获取当前岗位的限价级别, 判断当前岗位是否需要转审批
        String limitLevel = getPriceLimitLevel(request);
        Integer levelInt = Integer.valueOf(limitLevel);
        Integer minLimitLevelInt = Integer.valueOf(minLimitLevel);
        if (levelInt <= minLimitLevelInt) {
            returnMap = MapUtil.mapper(
                    "needPriceAudit", false,
                    "needPriceAuditList", new ArrayList<>(),
                    "limitLevel", enumeration
            );
        } else {
            List needPriceAuditList = new ArrayList();
            for (Integer integer = minLimitLevelInt; integer < levelInt; integer++) {
                needPriceAuditList.addAll(needPriceAuditMap.getOrDefault(integer+"",new ArrayList<>()));
            }
            // 根据规则 销售总监,副总裁,总裁走总裁审批, 店长走默认, 店助不做审批
            enumeration = enumerationRepository.findOne(
                JpaDsl.toCriteriaByEq(
                        "type.id", "priceLimit",
                        "code", getLevelCode(minLimitLevel,request.getBranchId())
                )
            ).orElse(null);
            returnMap = MapUtil.mapper(
                    "needPriceAudit", true,
                    "needPriceAuditList", needPriceAuditList,
                    "limitLevel", enumeration
            );
        }

        return new JSONObject(returnMap);

    }

    /**
     * 插入需要询价明细
     * @param needPriceAuditMap
     * @param servicePlanItem
     * @param level 限价级别
     * @return 返回级别
     */
    private String putNeedPriceAuditMap(Map<String, List<ServicePlanItem>> needPriceAuditMap, ServicePlanItem servicePlanItem,String level) {
        List<ServicePlanItem> servicePlanItems = needPriceAuditMap.getOrDefault(level, new ArrayList<>());
        servicePlanItems.add(servicePlanItem);
        needPriceAuditMap.put(level,servicePlanItems);
        return level;
    }


    private String getLevelCode(String minLimitLevel,String branchId) {
        //2022-04-26 销售总监需要踢出来
        if (minLimitLevel.equals("3")) {
            //没有配置总监直接转总裁
            List<Post> postList = SpringManager.getBean(PostRepository.class).findAllByBranchIdAndWorkPostId(branchId, "0001202");
            if (ObjectUtils.isEmpty(postList)) return "1";
            return "3";
        }

        return minLimitLevel.equals("4") ? minLimitLevel : "1";
    }


    private Product findProductById(String id){
        Product product = null;
        try {
            product = productRepository.findFirstByOrginID(id);
            if(product == null) throw new Exception("");
        }catch (Exception e){
            long minutes = System.currentTimeMillis() / 1000 / 60 % 60;
            long synTime = minutes % 5;
            throw new RuntimeException(id + " 商品同步中，请等候~");
        }
        return product;
    }

    public void confirmToApp(ServicePlan serviceplan){
        OutboxPayloadWrapper wrapper = new OutboxPayloadWrapper();
        wrapper.setSubscriber("servicePlan.server.confirmToApp");
        wrapper.setAggregateId("deliver" + serviceplan.getId());
        try {
            wrapper.setPayload(JSON.toJSONString(MapUtil.mapper("id",serviceplan.getId(),"state",serviceplan.getState())));
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        SpringManager.getBean(OutboxEventService.class).sendSaveEvent(wrapper);
    }


    /**
     * 通知app订单(
     * 入参：方案  + 类型 ： confirmType ： 0:确认,1:质检,2:终止
     * )
     * @param
     */
    @OutboxSubscriber(id="servicePlan.server.confirmToApp", name="推送方案数据给app")
    public void confirmToApp(OutboxPayloadWrapper outboxPayloadWrapper){
        JSONObject payloadJson = JSONObject.parseObject(outboxPayloadWrapper.getPayload());
        Optional.ofNullable(payloadJson.get("id")).orElseThrow(()->new RuntimeException("传入参数有误"));
        Optional.ofNullable(payloadJson.get("state")).orElseThrow(()->new RuntimeException("传入参数有误"));

        String state = payloadJson.getString("state");
        if("receivables".equals(state)) return;

        ServicePlan servicePlan = servicePlanRepository.findOne(payloadJson.getString("id"));

        planPushApp(state, servicePlan);

    }

    private void planPushApp(String state, ServicePlan servicePlan) {
        Integer confirmType = 0;
        //通知类型
        if("qualityTest".equals(state)){
            confirmType = 1;
        }else if("termination".equals(state)){
            confirmType = 2;
        }        //2021-02-24版本升级：归还偶尔会出问题，做一个验证，保证不推给app
//        checkProductReceiveAndReturn(servicePlan); //经验证已经可以在收款时自动归还
        //未服务的不推送
        List<ServicePlanItem> servicePlanItems = servicePlan.getServicePlanItems().stream()
                .filter(ServicePlanItem::isServiceState)
                .collect(Collectors.toList());
        List list = servicePlanItems.stream().map(servicePlanItem->{
            PartyRole customer = null;
            if(servicePlanItem.getCrossIC()!= null){
                if(servicePlanItem.getCrossIC().getCompany().getId().equals(servicePlan.getBelongDept().getCompany().getId())){ //
                    customer = servicePlanItem.getCrossIC().getPartner();
                }else{
                    customer = SpringManager.getBean(PartyRoleRepository.class).
                            findByPartyIdAndRoleId(servicePlanItem.getCrossIC().getCompany().getParty().getId(),"Customer");
                }
                if(customer == null) throw new RuntimeException("对应公司客户没设置");
            }
            PartyRole unitClient = servicePlanItem.getUnitClient();
            if(unitClient!=null){
                unitClient = findInvoiceForRules(servicePlan, unitClient);
            }

            return MapUtil.mapper(
                    "goodsCode",servicePlanItem.getProduct().getId(),
                    "goodsName",servicePlanItem.getProduct().getName(),
                    "number",servicePlanItem.getSaleQty(),
                    "receiveNumber",servicePlanItem.getQtyReceive(),
                    "isLaborGoods","20".equals(servicePlanItem.getProduct().getProductGroup().getId()) ? 1 : 0,
                    "originalPrice",servicePlanItem.getFloorPrice(),
                    "platformPrice",servicePlanItem.getBasePrice(),
                    "salePrice",servicePlanItem.getPftPriceUnit(),
                    "ordinal",servicePlanItem.getId(),
                    "stopNumber",servicePlanItem.getQtyEnd(),
                    "unitId",servicePlanItem.getUom().getId(),
                    "chargeCustomerCode", unitClient != null ? unitClient.getId() : customer == null ? null  : customer.getId(),
                    "chargeCustomerName", unitClient != null ? unitClient.getName() : customer == null ? null  : customer.getName(),
                    "chargeAmount",unitClient != null ? servicePlanItem.getSalesAmount() : servicePlanItem.getDeductionAmount(),
                    "discountAmount",servicePlanItem.getDiscountAmount()<0?0:servicePlanItem.getDiscountAmount(),
                    "companyCode",servicePlanItem.getCrossIC() == null ? null : servicePlanItem.getCrossIC().getCompany().getId(),
                    "customerCode",servicePlanItem.getCrossIC() == null ? null : servicePlanItem.getCrossIC().getPartner().getId(),
                    "customerName",servicePlanItem.getCrossIC() == null ? null : servicePlanItem.getCrossIC().getPartner().getName(),
                    "cooperateCostPrice",servicePlanItem.getCrossPriceCost(),
                    "fnSettlementPrice",servicePlanItem.getCrossAccountPrice(),
                    "customerPayPrice",servicePlanItem.getCrossCustomerPrice(),
                    "goodsClassifyCode",servicePlanItem.getCrossIC() == null ?
                            null : servicePlanItem.getCrossIC().getClassify() == null ?
                            null :servicePlanItem.getCrossIC().getClassify().getId() ,
                    "cooperateTypeCode",servicePlanItem.getCrossIC() == null ? null : servicePlanItem.getCrossIC().getId(),
                    "cooperateTypeName",servicePlanItem.getCrossIC() == null ? null : servicePlanItem.getCrossIC().getName(),
                    "settlementMethod",servicePlanItem.getCrossIC() == null ?
                            null : servicePlanItem.getCrossIC().getCrossPayType() == null ?
                            null :servicePlanItem.getCrossIC().getCrossPayType().getCode(),
                    "validMark",servicePlanItem.getCrossIC() == null ?
                            unitClient ==null?
                                    unitClient :1
                            : servicePlanItem.getCrossIC().isValid() ?
                                    1 : 0
            );
        }).collect(Collectors.toList());
        //如果状态是质检收款,并且来源单据为定损单,则需要重新取价格
        List goodsList = new ArrayList();
        if (Objects.equals("qualityTest",servicePlan.getState())
                && Objects.equals("LossQuotation", servicePlan.getSourceBusinessType())) {
            //需要计算是否有自费商品
            goodsList = addPayYourGoods(servicePlan);
        }
        if (goodsList.size() >0 ) list.addAll(goodsList);
        Map map = MapUtil.mapper(
                "isNeedReceipt",servicePlan.getBelongDept().getId().equals(servicePlan.getSaleDept().getId()) ? 1 : 0,
                "schemeNumber", servicePlan.getId(),
                "status",confirmType,
                "fnCustomerExpand",servicePlan.getFnCustomerExpand().getId(),
                "mobile",servicePlan.getFnCustomerExpand().getMobile(),
                "fromOrderNumber",(servicePlan.getSourceBusinessType() != null && "appOrder".equals(servicePlan.getSourceBusinessType()) &&servicePlan.getBelongDept().getId().equals(servicePlan.getSaleDept().getId())) ? servicePlan.getSourceFrom() : null,
                "carLicense",servicePlan.getFnCustomerExpand().getCarLicense(),
                "totalPrice", Arith.round(servicePlanItems.stream().mapToDouble(ServicePlanItem :: SaleAmount).sum(),2),
                "staffCode",returnSaler(servicePlan),
                "staffMobile",returnSalerMobile(servicePlan),
                //如果是来源定损得则需要传销售门店给app
                "storeCode",servicePlan.getBelongDept().getId(),
                "storeRemark",servicePlan.getDeptRemark(),
                "carOwnerRemark",servicePlan.getCustomerRemarks(),
                "isUseDiscount", servicePlanItems.stream().anyMatch(servicePlanItem -> servicePlanItem.getVipDiscountType() != null)? 1 : 0,
                "items",list
        );
        //定损来源需添加理赔信息以及金额
        if (Objects.equals("LossQuotation", servicePlan.getSourceBusinessType())) {
            //从新计算一下总金额,有可能定损会添加虚拟商品
            double totalAmount = 0;
            totalAmount = list.stream().mapToDouble(
                    item -> {
                        Map data = MapUtil.mapped(item);
                        if (data == null) return 0;
                        double qty = (double)data.get("number") -(double)data.get("stopNumber");
                        return Arith.mul(qty, (double)data.get("salePrice"));
                    }
            ).sum();
            addLossQuotationParam(servicePlan,map,totalAmount);
        }

        String result = this.invoke("pi.app.ext", MapUtil.mapper("headers", MapUtil.mapper("method", "v1/order/scheme", "action", "post"), "body", map));
        if (StringUtils.isEmpty(result) ||  "null".equals(result)) return;  // 遇到一种情况：返回值为 “null”

        JSONObject response = JSONObject.parseObject(result);
        try {
            if(!response.getBoolean("success")){
                throw new RuntimeException("AppError:" + response.toJSONString());
            }
        }catch (Exception e){
            throw new RuntimeException("AppError:" + response.toJSONString());
        }
    }

    private PartyRole findInvoiceForRules(ServicePlan servicePlan, PartyRole unitClient) {
        List<ClientInvoiceRules> invoiceRules = SpringManager.getBean(ClientInvoiceRulesRepository.class).findAll(JpaDsl.toCriteria("customer", "EQ", unitClient));
        ClientInvoiceRules rules = invoiceRules.stream().filter(clientInvoiceRules -> {
            return clientInvoiceRules.getClientInvoiceRulesItems().stream().anyMatch(clientInvoiceRulesItem -> clientInvoiceRulesItem.getDept().getId().equals(servicePlan.getBelongDept().getId()));
        }).findFirst().orElse(null);
        if (rules!=null){
            unitClient = rules.getCompany().getParty().getPartyRoleByType("Customer");
        }
        return unitClient;
    }

    private void checkProductReceiveAndReturn(ServicePlan servicePlan) {
        JSONArray arrayResult = new JSONArray();
        arrayResult.add(servicePlan.getId());
        JSONArray arrayTwo = SpringManager.getBean(ServicePlanDao.class).findForJudgeReturnTwo(arrayResult);
        if(arrayTwo.size() != 0) throw new RuntimeException("归还有误，回写方案数量有误,方案号：" + arrayTwo.getJSONObject(0).getString("SERVICE_PLAN_ID") + "，商品编码：" + arrayTwo.getJSONObject(0).getString("PRODUCT_ID"));
    }

    /**
     * 返回需要推送给app方案
     * @param servicePlan
     * @return
     */
    private ServicePlan findNeedQualityServicePlan(ServicePlan servicePlan) {
        if(servicePlan.getBelongDept().getId().equals(servicePlan.getSaleDept().getId())) return servicePlan;
        ServicePlan originServicePlan  = servicePlan.getServicePlanItems().stream().findFirst().get().getParentServicePlanItem().getServicePlan();
        return findNeedQualityServicePlan(originServicePlan);
    }

    /**
     * 添加定损自费商品
     * @param servicePlan
     * @param
     */
    private List addPayYourGoods(ServicePlan servicePlan) {
        List list = new ArrayList();
        LossQuotation quotation = lossQuotationRepository.findOne(servicePlan.getSourceFrom());
        double payYourAmountSix = quotation.computePayYourselfForSix();
        if (payYourAmountSix >0) packageYourGoods(list, payYourAmountSix, 6);
        double payYourAmountThirteen = quotation.computePayYourselfForThirteen();
        if  (payYourAmountThirteen >0) packageYourGoods(list, payYourAmountSix,13);
        return  list;
    }

    private void packageYourGoods(List list, double payYourAmount,double type) {
        LossAssessmentGoods assessmentGoods  =
                SpringManager.getBean(LossAssessmentGoodsRepository.class)
                        .findAll(JpaDsl.toCriteriaByEq("taxRate",type,"useType","1")).stream().findFirst().orElse(null);
        if (assessmentGoods == null) throw new RuntimeException("定损专用商品未定义,请联系后台人员!!!!");
        Product product = assessmentGoods.getProduct();
        list.add(
                //明细(商品编码,商品名称,数量,终止数量,是否工时费[0:否,1:是],原价,平台价,销售价,序号),计量单位
                MapUtil.mapper(
                        "goodsCode",product.getId(),
                        "goodsName",product.getName(),
                        "number",1,
                        "stopNumber",0,
                        "isLaborGoods","20".equals(product.getProductGroup().getId()) ? 1 : 0,
                        "originalPrice",payYourAmount,
                        "platformPrice",payYourAmount,
                        "salePrice",payYourAmount,
                        "ordinal",type,
                        "unitId",product.getUom().getId()
                )
        );
    }

    /**
     * 添加定损相关参数
     * @param servicePlan
     * @param map
     */
    private void addLossQuotationParam(ServicePlan servicePlan,Map map,Double totalAmount) {
        LossQuotation lossQuotation = lossQuotationRepository.findOne(servicePlan.getSourceFrom());
        CarAccident carAccident =SpringManager.getBean(CarAccidentRepository.class).findOne(lossQuotation.getCarAccident());
        String name = carAccident.getCarEvaluations().getClaimType().getName();
        if (name.equals("部分直赔")) name=businessAttributeValueRepository.findOne("LossQuotation.claimType.A").getName();
        Map claimInfo = MapUtil.mapper(
                "claimType", name,
                "insuranceCompanyCode",carAccident.getInsuranceCompany().getId(),
                "insuranceCompanyName",carAccident.getInsuranceCompany().getName(),
                "totalAmount",lossQuotation.isDiscountPayment() ?  Arith.round(Arith.mul(totalAmount,0.7), 2) : totalAmount, //如果定损单是七折赔付,则需要从新计算挂账金额
                "lossQuotationOrder",lossQuotation.getId(),
                "orderType",lossQuotation.getInnerBusinessType()
        );

        InsuranceCompany insuranceCompany = carAccident.getInsuranceCompany();  //保险公司信息
        Dept fixedLossDept = lossQuotation.getFixedLossDept();
        InsuranceCompanyDetail insuranceCompanyDetail = SpringManager.getBean(FixedLossToForeign.class)
                .getInsuranceCompanyToClient(insuranceCompany, fixedLossDept);
        claimInfo.put("client", insuranceCompanyDetail.getClient().getId());
        claimInfo.put("clientName", insuranceCompanyDetail.getClient().getName());
        claimInfo.put("lossStatus", checkFixedLoss(lossQuotation)); //添加定损状态
        map.put("totalPrice", totalAmount);
        map.put("claimInfo", claimInfo);
    }

    /**
     *  返回销售员手机
     * @param servicePlan
     * @return
     */
    public String returnSalerMobile(ServicePlan servicePlan) {
        List<String> staffList = servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem -> servicePlanItem.getMainSaler() != null && servicePlanItem.getMainSaler().getParty() != null)
                .map(servicePlanItem -> servicePlanItem.getMainSaler().getParty().queryMobileNumber())
                .collect(Collectors.toList());
        staffList.addAll(servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem -> servicePlanItem.getSupSaler() != null && servicePlanItem.getSupSaler().getParty() != null)
                .map(servicePlanItem -> servicePlanItem.getSupSaler().getParty().queryMobileNumber())
                .collect(Collectors.toList()));
        return staffList.stream().distinct().collect(Collectors.joining(","));
    }

    /**
     *  返回销售员
     * @param servicePlan
     * @return
     */
    public String returnSaler(ServicePlan servicePlan) {
        List<String> staffList = servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem -> servicePlanItem.getMainSaler() != null)
                .map(servicePlanItem -> servicePlanItem.getMainSaler().getId())
                .collect(Collectors.toList());
        staffList.addAll(servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem -> servicePlanItem.getSupSaler() != null)
                .map(servicePlanItem -> servicePlanItem.getSupSaler().getId())
                .collect(Collectors.toList()));
        return staffList.stream().distinct().collect(Collectors.joining(","));
    }

    /**
     *质检操作
     * @return
     */
    public Map qualityTestByApp(SimpleRequest simpleRequest){
        JSONObject jo = simpleRequest.getJO();
        //入参
        String servicePlanId = jo.getString("id");
        PartyRole role = MapUtil.getO(jo.getJSONObject("operator"),PartyRole.class);
        String type = jo.getString("type");
        JSONArray pic = jo.get("pic")!=null?jo.getJSONArray("pic"):new JSONArray();
        JSONArray items = jo.getJSONArray("items");
        boolean qualityFlag = jo.getBoolean("qualityFlag");
        //1.查询方案
        ServicePlan servicePlan = servicePlanRepository.findOne(servicePlanId);
        if(servicePlan.getQualityTestDate() != null) throw new RuntimeException("该方案已经完成质检，请重新刷新");
        List<ServicePlanItem> servicePlanItems = servicePlan.returnTypeItems(type);
        if(servicePlanItems.size() == 0 || servicePlanItems.size() != items.size())
            throw new RuntimeException("请刷新界面，相关商品发生变化");

        items.forEach((item)->{
            boolean flag = true;
            JSONObject tempJson = (JSONObject)item;
            for(ServicePlanItem servicePlanItem : servicePlanItems){
                if(servicePlanItem.getId().equals(tempJson.getString("id"))) {
                    flag = false;
                    servicePlanItem.setQualityTestDate(new Date());
                    servicePlanItem.setQualityTestUid(role);
                    servicePlanItem.setQualityFlag(qualityFlag);
                    servicePlanItem.setQualityTestPic(pic.toJSONString());
                    servicePlanItem.setSelected(true);
                    servicePlanItem.setWorkState("quality");
                }
            }
            if(flag) throw new RuntimeException("请刷新界面，相关商品发生变化");
        });
        //递归质检
        qualityTestRecursion(servicePlan);
        return MapUtil.mapper("success",true);
    }

    public Map qualityTestPlansByApp(SimpleRequest request){
        JSONObject jo = request.getJO();
        JSONArray planIds = jo.getJSONArray("planIds");
        Map map = checkCredit(planIds);
        if (!(Boolean) map.get("state"))throw new RuntimeException((String) map.get("msg"));
        String qualityDetail = qualityDetailService.generateQualityDetail(planIds, jo);
        return MapUtil.mapper("orderId",qualityDetail);
    }

    public Map qualityTest(ServicePlan servicePlan){
        // 质检递归完成所有方案(施工质检)
        qualityTestRecursion(servicePlan);
        return MapUtil.mapper("success",true);
    }

    private Map checkCredit(JSONArray planIds){
        Map<String,List<ServicePlan>> waitCheckPlanMap = new HashMap<>();
        for (Object id : planIds) {
            ServicePlan servicePlan = servicePlanRepository.findOne((String) id);
            //判断账期/信用额度
            boolean isLoss = "LossQuotation".equals(servicePlan.getSourceBusinessType());
            if (isLoss){
                qualityDetailService.checkCurAmountAndPeriod(servicePlan);  // 判断额度
                LossQuotation lossQuotation = SpringManager.getBean(LossQuotationRepository.class).findOne(servicePlan.getSourceFrom());
                //  定损来源并且不是 委托定损 或者不是 工单内协 的就返回
                if ( !"委托定损".equals(lossQuotation.getOrderType().getName()) && !"lossSomeAssist".equals(servicePlan.getPlanType()) ) break;
            }
            String belongDeptId = servicePlan.getBelongDept().getId();
            //判断是否基地单
            if (belongDeptId.equals(servicePlan.getSaleDept().getId())) break;
            //获取合作伙伴
            PartyRole company = servicePlan.getSaleDept().getCompany();
            String customer = company.getParty().getPartyRoleByType("Customer").getId();
            //添加进待判断信用额度列表
            List<ServicePlan> servicePlans = waitCheckPlanMap.get(belongDeptId +"-"+ customer);
            if (servicePlans==null)servicePlans = new ArrayList<>();
            servicePlans.add(servicePlan);
            waitCheckPlanMap.put(belongDeptId +"-"+ customer,servicePlans);

        }
        //循环判断处理
        Iterator<String> iterator = waitCheckPlanMap.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            String[] split = key.split("-");
            String deptId = split[0];
            String customer = split[1];
            PartyRole partyRole = SpringManager.getBean(PartyRoleRepository.class).findOne(customer);
            List<ServicePlan> servicePlans = waitCheckPlanMap.get(key);
            Map<String, Double> curAmount = this.invoke("retail.order.getCurAmount", mapper(
                    "dept", mapper("id", deptId),
                    "customer", mapper("id", customer)
            ));
            double balance = curAmount.get("curBalance") ;
            double platformCurBalance = curAmount.get("platformCurBalance") ;
            double allSalesAmount = servicePlans.stream().mapToDouble(ServicePlan::getSalesAmount).sum();
            Dept dept = deptRepository.findOne(deptId);
            if (allSalesAmount - platformCurBalance > 0){
                //`广州沥滘店`与`广州市车宝网络科技有限公司`的总额度不足，请先缴款至平台！
//                return mapper("state",false,"msg","["+ dept.getId() +"]部门与平台:"+partyRole.getName()+"["+ customer +"]信用额度不足！请先缴款至平台！");
                return mapper("state",false,"msg","'"+dept.getName()+"'与'"+partyRole.getName()+"'的总额度不足，请先缴款至平台！");
            }

            if (!partyRole.getParty().isRole("Company")) { /**内部客户不做额度检查**/
                if (allSalesAmount-balance > 0){
                    return mapper("state",false,"msg","公司【" + dept.getCompany().getId() + "】应收方'"+partyRole.getName()+"'挂账额度不足(剩余："+balance+")，请先做客户结算！");
                }
            }
        }
        return mapper("state",true,"msg","");

    }

    /**
     * 质检递归完成所有方案(施工质检)
     *
     * 2020-08-12  执行每个门店都需要质检各自项目，取消递归质检
     * @param servicePlan
     * @return
     */
    private ServicePlan qualityTestRecursion(ServicePlan servicePlan) {
//        ServicePlan originServicePlan = findOriginServicePlanByCurrentServicePlan(servicePlan);
        if(servicePlan.checkQualityResultByItem()){
            servicePlan.setQualityTestDate(new Date());
            addServicePlanLogger(servicePlan,"质检完成","");

            servicePlan.setState("qualityTest");
            //标记质检的方案里添加一个异步发件箱，处理未处理的领用单
            deletePRByPlanEnd(servicePlan);
        }
        servicePlan = updateOnly(servicePlan);
        createNXVoucher(servicePlan);
        if("qualityTest".equals(servicePlan.getState())){ //质检操作，如果不是质检都不推送
            confirmToApp(servicePlan);
        }
        return servicePlan;
    }
    private ServicePlan testQT(SimpleRequest request){
        JSONObject jo = request.getJO();
        ServicePlan servicePlan = servicePlanRepository.findOne(jo.getString("id"));
        List<PriceApprovalReport> currentApproval = auditNodeService.findCurrentApproval(servicePlan);
        int i=1/0;
        return servicePlan;
    }

    /**
     * 检查定损单是否完成
     * @return
     */
    private String checkFixedLoss(LossQuotation lossQuotation){
        String lossStatus = "0";
        if (lossQuotation != null && Objects.equals("businessAudit",lossQuotation.getState()))
            lossStatus = "1";
        return lossStatus;
    }

    /**
     * 内协方案生成工单
     * @param servicePlan
     * @return
     */
    public List<MaintenanceOrder> innerCreateMaintenanceOrder(ServicePlan servicePlan){
        List list = servicePlan.getServicePlanItems().stream().filter(servicePlanItem->servicePlanItem.isServiceState()
                    && ("20".equals(servicePlanItem.getProduct().getProductGroup().getId()) || servicePlanItem.isProductRule())).map(servicePlanItem->{
            return MapUtil.mapper(
                    "state", MaintenanceOrder.CONST_TABLE_STATE_CREATE,
                    "dispatcheState","none",
                    "lockState", "appOrder".equals(servicePlan.getSourceBusinessType()) || !isPickUpCar(servicePlan),
                    "servicePlanItem",MapUtil.mapped(servicePlanItem),
                    "belongDept",MapUtil.mapped(servicePlan.getBelongDept()),
                    "company",MapUtil.mapped(servicePlan.getBelongDept().getCompany()),
                    "fnCustomerExpand",MapUtil.mapped(servicePlan.getFnCustomerExpand()),
                    "product",MapUtil.mapped(servicePlanItem.getProduct()),
                    "uom",MapUtil.mapped(servicePlanItem.getUom()),
                    "platform",MapUtil.mapped(servicePlanItem.getPlatform()),
                    "saleQty",servicePlanItem.getSaleQty(),
                    "priceCostUnitInTax",servicePlanItem.getPriceCostUnitInTax(),
                    "platformPriceCosInTax",servicePlanItem.getPlatformPriceCosInTax(),
                    "productRule",servicePlanItem.isProductRule(),
                    "businessType",MaintenanceOrder.WORK_ORDER_INNER,
                    "workState",MaintenanceOrder.WORK_ORDER_WORKSTATE_WAIT,
                    "creator",servicePlan.getOperator1().getId(),
                    "businessTypeName","内协工单"
            );
        }).collect(Collectors.toList());
        if(list.isEmpty())return null;
        List<MaintenanceOrder> maintenanceOrders
                = this.invoke("fn.maintenance.createMaintenanceOrders", MapUtil.mapper("maintenanceOrders", list));

        //回写绑定关系（工时绑定工单）
//            servicePlan.getServicePlanItems().stream().filter(servicePlanItem->{
//                return "20".equals(servicePlanItem.getProduct().getProductGroup().getId());
//            }).forEach(servicePlanItem->{
//                MaintenanceOrder maintenanceOrder = maintenanceOrders.stream().filter((maintenanceOrder1)->{
//                    return maintenanceOrder1.getServicePlanItem().getId().equals(servicePlanItem.getId());
//                }).findFirst().orElse(null);
//                if(maintenanceOrder == null) throw new RuntimeException("miss");
//                servicePlanItem.setMaintenanceOrder(maintenanceOrder);
//            });
        //回写绑定关系（配件绑定工单）
        servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem -> servicePlanItem.getHigherLevelCode() != null)
                .forEach(servicePlanItem -> maintenanceOrders.stream()
                        .filter(maintenanceOrder -> maintenanceOrder.getServicePlanItem().getProduct().getId().equals(servicePlanItem.getHigherLevelCode()) && servicePlanItem.isServiceState())
                        .findFirst().ifPresent(maintenanceOrder1 -> servicePlanItem.setRelevanceWorkOrder(maintenanceOrder1.getId())));//TODO 观察一下ifPresent

        return maintenanceOrders;
    }


    //根据一个方案，产生内协门店方案
    public ServicePlan createServicePlanByInnerServicePlan(ServicePlan servicePlan){
        ServicePlan newServicePlan = new ServicePlan();
        ReflectUtil.copyAll(servicePlan, newServicePlan, "id");
        //内协主表需要更改字段
        newServicePlan.setSubmissionDate(null);
        newServicePlan.setSubmissionUid(null);
        newServicePlan.setBelongDept(servicePlan.getSaleDept());
        newServicePlan.setSaleDept(servicePlan.getSaleDept());
        newServicePlan.setServiceDept(servicePlan.getBelongDept());
        newServicePlan.setCompany(servicePlan.getSaleDept().getCompany());
        newServicePlan.setPickUpTypeS(null);
        //接车信息
        newServicePlan.setGetCarInfo(null);
        newServicePlan.setPickCarId(null);
        newServicePlan.setPickCarType(null);
        newServicePlan.setPickCarDate(null);
        newServicePlan.setPickCarName(null);
        checkCarInfo(newServicePlan);

        //判断该门店+车是否有唯一的接车拓展信息，有的话，直接用该门店的，没有的话，公用来源门店的
        FnCustomerExpand newFnCustomerExpand = findValidServiceFnCustomerExpand(newServicePlan.getBelongDept(),newServicePlan.getFnCustomerExpand().getCarLicense());
        if(newFnCustomerExpand != null)
            newServicePlan.setFnCustomerExpand(newFnCustomerExpand);
        String vendorCode = servicePlan.getFnCustomerExpand().getVendorCode();
        String carLicense = servicePlan.getFnCustomerExpand().getCarLicense();
        Object mobile = servicePlan.getCustomer().get("mobile");
        String deptId = servicePlan.getSaleDept().getId();
        JSONArray jgArray = serviceToForeign.getXS51(
                newServicePlan.getServicePlanItems().stream()
                        .filter(servicePlanItem -> servicePlanItem.getOldInquiryNumber() == null)
                        .map(servicePlanItem -> MapUtil.mapper(
                                "uniqueIdentify", servicePlanItem.getId(),
                                "PLID", servicePlanItem.getProduct().getClassify().getId(),
                                "SPID", servicePlanItem.getProduct().getId(),
                                "HZLXID", newServicePlan.getCooperationType() == null ? null : newServicePlan.getCooperationType().getId(),
                                "PPID", servicePlanItem.getProduct().getBrand().getId(),   //品牌找品质
                                "PZID", servicePlanItem.getProduct().getBrand().getQuality() == null ? null : servicePlanItem.getProduct().getBrand().getQuality().getCode(),
                                "XSZZID", newServicePlan.getBelongDept().getCompany().getId(),
                                "GSID", newServicePlan.getBelongDept().getCompany().getId(),
                                "FNKHID", newServicePlan.getFnCustomerExpand().getUnitClientId(),
                                "CLFWDJID", ((CarServiceLevel) (SpringManager.getBean(CarServiceLevelService.class).findByCarConfigurationId(newServicePlan.getFnCustomerExpand().getJekunModelCode()))).getId(),
                                //"MDLXID", newServicePlan.getBelongDept().getDeptType().getId(),
                                "FNVIPJBID", newServicePlan.getFnCustomerExpand().getCustomerLevelId(),
                                "FNVIPSFID", newServicePlan.getFnCustomerExpand().getUserRoleId(),
                                "CGZZID", newServicePlan.getServiceDept().getCompany().getId(),
                                "JLDW", servicePlanItem.getUom().getName(),
                                "JLDWID", servicePlanItem.getUom().getId(),
                                "JRS", vendorCode,
                                "CPHM", carLicense,
                                "SJHM", mobile,
                                "XSMD", deptId,
                                "YYMS", newServicePlan.getBelongDept().getCompany().getParty().getCorporate().getOperation().getCode(),
                                "NYYMS", newServicePlan.getBelongDept().getCompany().getParty().getCorporate().getOperation().getId(),
                                "SYGSID", servicePlanItem.getPlatform().getId(),
                                "SQID", SpringManager.getBean(StoreService.class).findBusinessCircleByDept(newServicePlan.getSaleDept()).getId(),
                                "XYGSID", newServicePlan.getBelongDept().getCompany().getId()
                        )).collect(Collectors.toList()),true);


        jgArray.addAll(serviceToForeign.getXJ51(newServicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem -> servicePlanItem.getOldInquiryNumber() != null)
                .map(servicePlanItem -> MapUtil.mapper(
                        "uniqueIdentify", servicePlanItem.getId(),
                        "GSID", newServicePlan.getBelongDept().getCompany().getId(),
                        "XYGSID", newServicePlan.getBelongDept().getCompany().getId(),
                        "SYGSID", newServicePlan.getServiceDept().getCompany().getId(),
                        "YYMS", newServicePlan.getBelongDept().getCompany().getParty().getCorporate().getOperation().getCode(),
                        "NYYMS", newServicePlan.getBelongDept().getCompany().getParty().getCorporate().getOperation().getId(),
                        "SPID", servicePlanItem.getProduct().getId(),
                        "PLID", servicePlanItem.getProduct().getClassify().getId(),
                        "JLDW", servicePlanItem.getUom().getName(),
                        "FNKHID", newServicePlan.getFnCustomerExpand().getUnitClientId(),
                        "FNVIPJBID", newServicePlan.getFnCustomerExpand().getCustomerLevelId(),
                        "FNVIPSFID", newServicePlan.getFnCustomerExpand().getUserRoleId(),
                        "XSDJ", servicePlanItem.getInquiryPriceUnit(),
                        "XSXJ", servicePlanItem.getInquiryPriceLimit(),
                        "P001", servicePlanItem.getInquiryPurchaseUnit()
                )).collect(Collectors.toList())));

        String COMPANY_ID = newServicePlan.getCompany().getId();
        String OPERATION = newServicePlan.getCompany().getParty().getCorporate().getOperation().getDescription();

        List servicePlanItems = new ArrayList();
        servicePlan.getServicePlanItems().stream().filter(ServicePlanItem::isServiceState).forEach(servicePlanItem->{
            ServicePlanItem newServicePlanItem = new ServicePlanItem();
            newServicePlanItem = ReflectUtil.clone(servicePlanItem, "id","innerBusinessKey","servicePlan");
            boolean flag = true;
            for(int i =0 ;i<jgArray.size();i++){
                JSONObject item = jgArray.getJSONObject(i);
                if(item.getString("uniqueIdentify").equals(servicePlanItem.getId())){
                    newServicePlanItem.setPrimaryPriceUnit(item.getDouble("primaryPriceUnit"));
                    newServicePlanItem.setPrimaryPriceUnitShow(item.getDouble("primaryPriceUnit"));
                    newServicePlanItem.setPriceUnit(item.getDouble("priceUnit"));
                    newServicePlanItem.setPftPriceUnit(item.getDouble("pftPriceUnit"));
                    newServicePlanItem.setManagementFeeRate(item.getDouble("managementFeeRate"));
                    newServicePlanItem.setFloorPrice(item.getDouble("floorPrice"));
                    newServicePlanItem.setClerkPriceLimit(item.getDouble("clerkPriceLimit"));
                    newServicePlanItem.setShopOwnerPriceLimit(item.getDouble("shopOwnerPriceLimit"));
                    newServicePlanItem.setCsoPriceLimit(item.getDouble("csoPriceLimit"));
                    newServicePlanItem.setBasePrice(item.getDouble("basePrice"));
                    newServicePlanItem.setPriceSource(item.getString("priceSource"));
                    newServicePlanItem.setDiscountRate(item.getDouble("discountRate"));
                    newServicePlanItem.setSupplyChainManagement(item.getDouble("supplyChainManagement") == null ? 0 : item.getDouble("supplyChainManagement") );
                    flag = false;
                }
            }
            if(flag) throw new RuntimeException("存在商品未取到价格,商品名称：" + newServicePlanItem.getProduct().getName());
            if(newServicePlanItem.getPftPriceUnit() <= 0) throw new RuntimeException("存在商品未取到价格,商品名称：" + newServicePlanItem.getProduct().getName());
            newServicePlanItem.setServicePlan(newServicePlan);
            innerPlanGetPriceCostUnit(newServicePlanItem,servicePlanItem);
            newServicePlanItem.setPlatformPriceCosInTax(servicePlanItem.getPftPriceUnit());
            newServicePlanItem.setReferTax(servicePlanItem.getPftPriceUnit());
            newServicePlanItem.setEstimatedCommission((Double)(SpringManager.getBean(TCService.class).obtainEstimatedCommission(
                    newServicePlanItem.getProduct().getId(),
                    newServicePlanItem.getProduct().getClassify().getId(),
                    newServicePlanItem.getServeType().getId(),
                    newServicePlanItem.getProduct().getBrand().getId(),
                    newServicePlanItem.getReferTax(),
                    newServicePlanItem.getPftPriceUnit(),
                    newServicePlanItem.getFloorPrice(),
                    newServicePlanItem.getPriceUnit(),
                    COMPANY_ID,OPERATION
            )));
            newServicePlanItem.setAssistType(businessAttributeValueRepository.findOne("ServicePlanItem.assistType.inner"));
            if(!newServicePlan.getBelongDept().getCompany().getId().equals(newServicePlan.getServiceDept().getCompany().getId())){ //跨公司重取仓库
                newServicePlanItem.setLocation(
                        SpringManager.getBean(LocationService.class).findLocationByDept(newServicePlan.getBelongDept(),newServicePlanItem.isProductRule())
                );
            }
            newServicePlanItem.setId(null);
            newServicePlanItem.setHigherLevelCode(null);
            servicePlanItems.add(newServicePlanItem);

        });
        newServicePlan.setServicePlanItems(servicePlanItems);
        return newServicePlan;
    }

    /**
     * 获取内协门店方成本单价
     * @param comm
     * @param inner
     */
    public void innerPlanGetPriceCostUnit(ServicePlanItem comm,ServicePlanItem inner){
        boolean isEqCmpany = comm.getServicePlan().getCompany().getId().equals(inner.getServicePlan().getCompany().getId());
        boolean isWorkHour = comm.getProduct().getProductGroup().getId().equals("20");
        double pftPriceUnit = inner.getPftPriceUnit();
        if (isEqCmpany){
            if (isWorkHour){
                comm.setPriceCostUnitInTax(0);
                comm.setPriceCostUnitExTax(0);
            }else {
                comm.setPriceCostUnitInTax(inner.getPriceCostUnitInTax());
                comm.setPriceCostUnitExTax(inner.getPriceCostUnitExTax());
            }
        }else {
            comm.setPriceCostUnitInTax(pftPriceUnit);
            comm.setPriceCostUnitExTax(pftPriceUnit);
        }
    }

    public boolean isNeedReferTax(ServicePlan newServicePlan, ServicePlanItem servicePlanItem) {
        return newServicePlan.getServiceDept().getCompany().getId().equals(newServicePlan.getSaleDept().getCompany().getId())&&"20".equals(servicePlanItem.getProduct().getProductGroup().getId());
    }

    /**
     * erp前端界面入口
     * @param simpleRequest
     * @return
     */
    public ServicePlan terminationServicePlanAccess(SimpleRequest simpleRequest){
        ServicePlan servicePlan = simpleRequest.getO(ServicePlan.class);
        //第一个方案检测是否能从带单据终止
        servicePlan.getServicePlanItems().forEach(servicePlanItem->{
            if(servicePlanItem.isSelected()){
                if("inner".equals(servicePlanItem.getAssistType().getCode())) throw new RuntimeException("商品转了内协，不能从该单据终止，商品：" + servicePlanItem.getProduct().getName());
            }
        });
        return terminationServicePlan(servicePlan);
    }


    /**
     * 根据明细行，终止单据
     *
     * +配件冻结数，都是根据方案的所属门店和服务门店是否一致+冻结数，有老框架来源的
     *
     * @param servicePlan
     * @return
     */
    public ServicePlan terminationServicePlan(ServicePlan servicePlan){
        ServicePlan originServicePlan = findOriginServicePlanByCurrentServicePlan(servicePlan);
        if(originServicePlan != null){
            boolean flag = true;
            for(ServicePlanItem originServicePlanItem : originServicePlan.getServicePlanItems()){
                for(ServicePlanItem currentServicePlanItem : servicePlan.getServicePlanItems()){
                    if(currentServicePlanItem.isSelected() && currentServicePlanItem.getParentServicePlanItem().getId().equals(originServicePlanItem.getId())){
                        originServicePlanItem.setQtyEndTemp(currentServicePlanItem.getQtyEndTemp());
                        originServicePlanItem.setSelected(true);
                        flag = false;
                    }
                }
            }
            if(flag) throw new RuntimeException("来源明细有误，终止失败");
            originServicePlan = terminationServicePlan(originServicePlan);
        }
        //验证终止行是否能够进行终止
        checkCanTermination(servicePlan);
        //处理前工单(需放在方案更新前，不然方案选中状态会取消。或者先过滤出来)
        List<MaintenanceOrder> maintenanceOrders = terminationCurrentMaintenanceOrderByServicePlan(servicePlan);
        // 回写方案明细施工状态
        workStateTermination(maintenanceOrders,servicePlan);
        //处理当前方案
        servicePlan = terminationCurrentServicePlan(servicePlan);
        //通知app调用接口
        confirmToApp(servicePlan);
        return servicePlan;
    }

    /**
     * 方案终止，终止工单
     * @param servicePlan
     * @return
     */
    private List<MaintenanceOrder> terminationCurrentMaintenanceOrderByServicePlan(ServicePlan servicePlan) {
        //当前如果方案确认，有工单的终止
        List<MaintenanceOrder> maintenanceOrders = servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem -> servicePlanItem.returnMaintenanceOrder() != null && servicePlanItem.isSelected())
                .map(servicePlanItem -> {
                    MaintenanceOrder maintenanceOrder = servicePlanItem.returnMaintenanceOrder();
                    maintenanceOrder.setOperator1(servicePlan.getOperator1());
                    if (servicePlanItem.getQtyEndTemp() == servicePlanItem.getSaleQty()) {
                        maintenanceOrder.setSelected(true);
                    }
                    return maintenanceOrder;
                }).collect(Collectors.toList());

        if(maintenanceOrders.size() == 0)return maintenanceOrders;

        return maintenanceOrderService.terminationMaintenanceOrders(maintenanceOrders);
    }

    /**
     * 根据方案寻找来源方案
     */
    public ServicePlan findOriginServicePlanByCurrentServicePlan(ServicePlan servicePlan){
        List<ServicePlan> servicePlans = servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem -> servicePlanItem.getParentServicePlanItem() != null)
                .map(servicePlanItem -> servicePlanItem.getParentServicePlanItem().getServicePlan())
                .collect(Collectors.toList());

        if(servicePlans.size() == 0) return null;

        Map map = servicePlans.stream().collect(groupingBy(ServicePlan::getId));
        if(map.size() != 1) throw new RuntimeException("查找来源方案有误，请检查");
        return servicePlans.stream().findFirst().get();
    }

    /**
     *方案终止，终止方案
     * @param servicePlan
     * @return
     */
    private ServicePlan terminationCurrentServicePlan(ServicePlan servicePlan) {

        //是否需要写冻结数
        boolean accountFlag = servicePlan.getBelongDept().getId().equals(servicePlan.getServiceDept().getId()) ;

        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            //取消掉已经有终止时间的商品(前端控制有误，后端取消掉)
            if (servicePlanItem.getTerminationDate() != null && servicePlanItem.isSelected())
                servicePlanItem.setSelected(false);
            if (servicePlanItem.isSelected()) {
                //判断是否能够冻结
                if (servicePlanItem.getQtyEndTemp() < servicePlanItem.getQtyEnd())
                    throw new RuntimeException("本次终止数量必须大于之前终止数量");
                //1.写冻结数 账目
                writeProductFrozen(servicePlan, accountFlag, servicePlanItem);
                //2.设置已终止数目
                servicePlanItem.setQtyEnd(servicePlanItem.getQtyEndTemp());
                //检测终止数量(分别设置该明细为完成状态，终止状态，未完成状态)
                if ("termination".equals(servicePlanItem.returmItemState())) { //全部终止，设置终止
                    servicePlanItem.setTerminationUid(servicePlan.getOperator1());
                    servicePlanItem.setTerminationDate(new Date());
                    servicePlanItem.setUnitClient(null);  // 【服务方案-异业合作】终止时自动清空已选择的单位客户
                    servicePlanItem.setState("termination");  // 回写方案明细状态
                } else if ("finish".equals(servicePlanItem.returmItemState())) { //当前明细为完成状态
                    servicePlanItem.setFinishDate(new Date());
                    servicePlanItem.setQualityTestUid(servicePlan.getOperator1());
                    servicePlanItem.setQualityTestDate(new Date());
                    servicePlanItem.setQualityFlag(true);
                }
            }
        });
        //检测整个工单是否(完成or终止)
        if ("finish".equals(servicePlan.checkResultByItem())) {
            servicePlan.setFinishWork(true);
            //判断是否已经完成质检（自动完成质检）
            if (servicePlan.checkQualityResultByItem()) {
                servicePlan.setQualityTestDate(new Date());
                servicePlan.setState("qualityTest");
                //保证日志顺序
                addServicePlanLogger(servicePlan,"终止","");
                addServicePlanLogger(servicePlan,"质检完成","");
                servicePlan.setWrite(false);
            }
        } else if ("termination".equals(servicePlan.checkResultByItem())) {
            servicePlan.setState("termination");
            servicePlan.setTerminationUid(servicePlan.getOperator1());
            servicePlan.setTerminationDate(new Date());
            this.submitSynGYSXJD(servicePlan.getId());
        }
        //异步调用终止要货
        asynchronousEndRequire(servicePlan);
        createNXVoucher(servicePlan);
        //如果是定损来源的服务方案需要处理定损单
        clearOrderNumber(servicePlan);
        terminationClearLossQuotationPlan(servicePlan);
        return updateServicePlanForMoney(servicePlan);
    }

    /**
     * 异步调用终止要货
     * @param servicePlan
     */
    private void asynchronousEndRequire(ServicePlan servicePlan) {
        OutboxPayloadWrapper wrapper = new OutboxPayloadWrapper();
        wrapper.setSubscriber("servicePlan.server.endRequire");
        wrapper.setAggregateId("ser" + servicePlan.getId());
        try {
            wrapper.setPayload(servicePlan.getId());
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        SpringManager.getBean(OutboxEventService.class).sendSaveEvent(wrapper);
    }

    private void writeProductFrozen(ServicePlan servicePlan, boolean accountFlag, ServicePlanItem servicePlanItem) {
        if (accountFlag && "10".equals(servicePlanItem.getProduct().getProductGroup().getId())) {
            //  本次需要增加的冻结数   servicePlanItem.getQtyEndTemp() > servicePlanItem.getQtyEnd()
            productAccountService.setProductFrozen(
                    servicePlanItem.getProduct(), servicePlanItem.getLocation(),
                    servicePlanItem.getUom(),
                    -1 * (servicePlanItem.getQtyEndTemp() - servicePlanItem.getQtyEnd()),
                    servicePlan.getInnerBusinessType(), servicePlan.getId(),
                    servicePlanItem.getId(), "服务方案终止",
                    servicePlanItem.getLocation().getCompany(), servicePlan.getInnerBusinessType(), servicePlan.getInnerBusinessKey(), servicePlanItem.getInnerBusinessKey()
            );
        }
    }


    //领用回写问题
    public ServicePlan rewriteServicePlanByProductReceive(ProductReceive productReceive,PartyRole role){
        ServicePlan servicePlan = null;
        try {
            servicePlan = productReceive.getProductReceiveItems().stream().findFirst().get().getServicePlanItem().getServicePlan();
            if(servicePlan == null) throw new RuntimeException("未找到原服务方案，服务方案号：" + productReceive.getSource());
        }catch (Exception e){
            throw new RuntimeException("领用回写方案有误，未找到来源方案");
        }
        List<ServicePlanItem> servicePlanItems = servicePlan.getServicePlanItems();
        productReceive.getProductReceiveItems().forEach(productReceiveItem -> {

            ServicePlanItem sourceItem =  servicePlanItems.stream().filter(servicePlanItem ->
                    servicePlanItem.getId().equals(productReceiveItem.getServicePlanItem().getId()) && servicePlanItem.isServiceState()).findFirst().orElseGet(null);
            if (sourceItem == null) throw new RuntimeException("未找到原服务方案商品，商品名称：" + productReceiveItem.getProduct().getName()
                    + "原明细行号：" + productReceiveItem.getServicePlanItem().getId() );

            sourceItem.addQtyReceive(productReceiveItem.getQtyReceive());

            if(sourceItem.getSaleQty() == sourceItem.getQtyEnd() + sourceItem.getQtyReceive()
                    && sourceItem.getSaleQty() != sourceItem.getQtyEnd()){
                sourceItem.setFinishDate(new Date());
                sourceItem.setQualityTestDate(new Date());
                sourceItem.setQualityFlag(true);
                sourceItem.setQualityTestUid(role);
                sourceItem.setSelected(true);
            }
        });

        servicePlan.setOperator1(role);
        String receive ="配件领用" ;
        if ("APP扫码领用".equals(productReceive.getRemark())) {
            receive="扫码领用";
        }
        addServicePlanLogger(servicePlan,receive,productReceive.getId());
        servicePlan = rewriteBackServicePlanByProductReceive(servicePlan);
        confirmToApp(servicePlanRepository.findOne(servicePlan.getId()));
        return servicePlan;
    }

    /**
     * 回写所有方案
     * @param servicePlan
     * @return
     */
    private ServicePlan rewriteBackServicePlanByProductReceive(ServicePlan servicePlan) {
        PartyRole role = servicePlan.getOperator1();
        ServicePlan originServicePlan = findOriginServicePlanByCurrentServicePlan(servicePlan);
        if (originServicePlan != null) {
            servicePlan.getServicePlanItems().stream().filter(ServicePlanItem::isSelected)
                    .forEach(servicePlanItem -> {
                        originServicePlan.getServicePlanItems().forEach(originServicePlanItem -> {
                            if (originServicePlanItem.getId().equals(servicePlanItem.getParentServicePlanItem().getId())) {
                                originServicePlanItem.setQtyReceive(servicePlanItem.getQtyReceive());
                                if (originServicePlanItem.getSaleQty() == originServicePlanItem.getQtyEnd() + originServicePlanItem.getQtyReceive()
                                        && originServicePlanItem.getSaleQty() != originServicePlanItem.getQtyEnd()) {
                                    originServicePlanItem.setFinishDate(new Date());
                                    originServicePlanItem.setQualityTestDate(new Date());
                                    originServicePlanItem.setQualityFlag(true);
                                    originServicePlanItem.setQualityTestUid(role);
                                    originServicePlanItem.setSelected(true);
                                }
                            }
                        });
                    });
            rewriteBackServicePlanByProductReceive(originServicePlan);
        }
        //检测是否全部完工，更新整个工单状态
        if("finish".equals(servicePlan.checkResultByItem())){
            servicePlan.setFinishWork(true);
            if(servicePlan.checkQualityResultByItem()){
                servicePlan.setQualityTestDate(new Date());
                addServicePlanLogger(servicePlan,"质检完成","");
                servicePlan.setState("qualityTest");
                //标记质检的方案里添加一个异步发件箱，处理未处理的领用单
                deletePRByPlanEnd(servicePlan);
            }
        }
        servicePlan = updateOnly(servicePlan);
        createNXVoucher(servicePlan); //领用导致的质检
        if("qualityTest".equals(servicePlan.getState())){ //通知APP
            confirmToApp(servicePlan);
        }
        return servicePlan;
    }

    private void reWriteSourcePlan(ServicePlan servicePlan, String operate) {
        if (servicePlan.checkInnerServicePlan()) {
            servicePlan.getServicePlanItems().stream()
                    .map(ServicePlanItem::getParentServicePlanItem)
                    .filter(Objects::nonNull)
                    .map(ServicePlanItem::getServicePlan)
                    .distinct()
                    .forEach(servicePlan1 -> addServicePlanLogger(servicePlan1, operate, ""))
            ;
        }
    }

    /**
     * 配件归还
     * @param productReturn
     * @return
     */
    public void rewriteServicePlanByProductReturn(ProductReturn productReturn){
        Map groupMap = productReturn.getProductReturnItems().stream()
                .collect(groupingBy(productReturnItem-> productReturnItem.getProductReceiveItem().getServicePlanItem().getServicePlan().getId()));
        //分组回写领用数量
        groupMap.forEach((k,v)->{
            List<ProductReturnItem> productReturnItems
                    = new ArrayList<ProductReturnItem>((Collection<? extends ProductReturnItem>) v);
            ServicePlan servicePlan = servicePlanRepository.findOne((String) k);
            if(servicePlan.getQualityTestDate() != null) throw new RuntimeException("方案已经质检，不允许归还");

            servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
                productReturnItems.forEach(productReturnItem -> {
                    if(productReturnItem.getProductReceiveItem().getServicePlanItem().getId().equals(servicePlanItem.getId())){
                        servicePlanItem.addQtyReceive(-1 * productReturnItem.getQtyReturn());
                        servicePlanItem.setFinishDate(null);
                        servicePlanItem.setQualityTestDate(null);
                        servicePlanItem.setQualityTestUid(null);
                        servicePlanItem.setQualityFlag(false);
                        servicePlanItem.setSelected(true);

                    }
                });
            });
            rewriteBackServicePlanByProductReturn(servicePlan);
            confirmToApp(servicePlanRepository.findOne(servicePlan.getId()));
        });
    }


    /**
     * 回写所有方案(归还)
     * @param servicePlan
     * @return
     */
    private ServicePlan rewriteBackServicePlanByProductReturn(ServicePlan servicePlan) {
        ServicePlan originServicePlan = servicePlan.getServicePlanItems().stream().findFirst().get().getParentServicePlanItem() != null ?
                servicePlan.getServicePlanItems().stream().findFirst().get().getParentServicePlanItem().getServicePlan() : null;
        if(originServicePlan != null){
            servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
                if(servicePlanItem.isSelected()){
                    originServicePlan.getServicePlanItems().forEach(originServicePlanItem -> {
                        if(originServicePlanItem.getId().equals(servicePlanItem.getParentServicePlanItem().getId())){
                            originServicePlanItem.setQtyReceive(servicePlanItem.getQtyReceive());
                            originServicePlanItem.setSelected(true);
                            clearQualityTest(originServicePlanItem);
                        }
                    });
                }
            });
            rewriteBackServicePlanByProductReceive(originServicePlan);
        }
        servicePlan.setFinishWork(false);
        servicePlan = updateOnly(servicePlan);
        return servicePlan;
    }

    @OutboxSubscriber(id="servicePlan.server.receivablesList", name="收款回写方案")
    public void receivablesList(OutboxPayloadWrapper wrapper){
        List<String> list = JSONArray.parseArray(wrapper.getPayload()).stream().map(item -> (String) item).collect(Collectors.toList());
        List<ServicePlan> servicePlans = receivablesRecursion(list);
        servicePlans.forEach(this::receivables);
    }

    /**
     * 终止规则：
     * 方案该商品终止n个，检测该商品对应要货单的可终止数量m。n>=m,终止m个，m>n,终止n个
     *
     * @param wrapper
     */
    @OutboxSubscriber(id="servicePlan.server.endRequire", name="方案终止终止要货单")
    public void endRequire(OutboxPayloadWrapper wrapper){
        ServicePlan servicePlan = servicePlanRepository.findOne(wrapper.getPayload());     //根据方案号检测是否有对应的要货单，如果有的话，
        List<ProductRequire> productRequires =
                SpringManager.getBean(ProductRequireRepository.class).findAll(JpaDsl.toCriteriaByEq("source", servicePlan.getId(), "sourceBusinessType", "servicePlan","approveDate",null,"deleteDate",null));

        if (productRequires != null || productRequires.size() != 0) {
            Map<String, List<ServicePlanItem>> mapItems = servicePlan.getServicePlanItems().stream().filter(servicePlanItem -> {
                return servicePlanItem.getQtyEnd() > 0 ;
            }).collect(Collectors.groupingBy(servicePlanItem -> servicePlanItem.getProduct().getId()));

            productRequires.stream().forEach(productRequire -> {
                List<Map> productRequireItemMaps = productRequire.getProductRequireItems().stream().filter(productRequireItem -> {
                    //当前商品，过滤可终止数量小于等于0的要货明细
                    return productRequireItem.canEndQty() > 0 && mapItems.containsKey(productRequireItem.getProduct().getId());
                }).map(productRequireItem -> {
                    double mQty = mapItems.get(productRequireItem.getProduct().getId()).stream().mapToDouble(ServicePlanItem::getQtyEnd).sum();
                    productRequireItem.setRemark("门店终止方案导致要货单终止");
                    Enumeration terminationReson = SpringManager.getBean(EnumerationRepository.class).findByTypeAndValue("写备注(上面原因除外的)", "terminationReson");
                    productRequireItem.setTerminationReson(terminationReson);
                    productRequireItem.setQtyEnd(mQty >= productRequireItem.canEndQty() ?  productRequireItem.canEndQty() : mQty);
                    return MapUtil.mapper("remark", "门店终止方案导致要货单终止");
                }).collect(Collectors.toList());
                PartyRole system = SpringManager.getBean(PartyRoleRepository.class).findOne("system");
                productRequire.setOperator(system.getId());
                productRequire.setRepealId(system);
                productRequire.setRepealDate(new Date());
                try {
                    if(productRequireItemMaps.size() != 0)
                            this.invoke("stock.productRequire.repeal", productRequire);
                }catch (Exception e){
                    throw new RuntimeException(e.getMessage() + "入参：【"+MapUtil.mapper("id",productRequire.getId(),"productRequireItems",productRequireItemMaps).toString()+"】");
                }
            });
        }

    }

    private List<ServicePlan> receivablesRecursion(List<String> list){
        List<ServicePlan> servicePlans = new ArrayList<>();
        if(list.size()>0){
            ServicePlanItem servicePlanItem = servicePlanItemRepository.findOne(list.stream().findFirst().get());
            ServicePlan servicePlan = servicePlanItem.getServicePlan();
            servicePlans.add(servicePlan);
            servicePlan.getServicePlanItems().forEach(servicePlanItem1 -> list.remove(servicePlanItem1.getId()));
            servicePlans.addAll(receivablesRecursion(list));
        }
        return servicePlans;
    }

    /**
     * 跟顾客收款调用，回写方案状态
     * @param servicePlan
     * @return
     */
    private ServicePlan receivables(ServicePlan servicePlan){
        if("receivables".equals(servicePlan.getState())) return servicePlan;
        if(!"qualityTest".equals(servicePlan.getState())) throw new RuntimeException("非质检状态方案，不能更新为收款状态");

        List<String> itemIds = servicePlan.getServicePlanItems().stream().map(ServicePlanItem::getId).collect(Collectors.toList());
        List<ServicePlan> servicePlans = servicePlanRepository.findServicePlan(itemIds);
        Map map = servicePlans.stream().collect(groupingBy(ServicePlan::getId));
        if(map.size() != 0){
            map.forEach((k,v) -> {
                ServicePlan resultServicePlan = MapUtil.getO(((List)v).stream().findFirst().get(),ServicePlan.class);
                receivables(resultServicePlan);
            });
        }
        //日志写入收款人
        writeReceivablesLogger(servicePlan);

        servicePlan.setState("receivables");
        servicePlan.setReceivableDate(new Date());
        if ("LossQuotation".equals(servicePlan.getSourceBusinessType())&&servicePlan.getSourceFrom()!=null){
            LossQuotation lossQuotation = lossQuotationRepository.findOne(servicePlan.getSourceFrom());
            if (lossQuotation.getReceivableDate()==null)lossQuotation.setReceivableDate(new Date());
        }
        return updateOnly(servicePlan);
    }

    private void writeReceivablesLogger(ServicePlan servicePlan) {
        RetailOrder retailOrder = null;
        try {
            retailOrder = invoke("retail.order.findRetailOrderByOriginOrSource", mapper("source", servicePlan.getId()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (retailOrder!=null){
            User user =SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id",retailOrder.getClerk().getId())).stream().findFirst().orElse(null);
            assert user != null;
            addServicePlanLogger(servicePlan,"收款完成","",user.getId());
        }
        if (retailOrder==null)addServicePlanLogger(servicePlan,"收款完成","");
    }

    /**
     * 将生成凭证的数据中的批次与供应商回写
     *
     * @param request list
     */
    @Listener(topic = "event:ser.serverPlanItem.setBatchAndSupplier")
    public void setBatchAndSupplier(SimpleRequest request) {
        JSONArray serviceItemList = request.getJA();

        serviceItemList.forEach(item -> {
            JSONObject json = (JSONObject) item;
            String servicePlanItemId = json.getString("servicePlanItemId");
            String supplierId = json.getString("supplierId");
            String classification = json.getString("classification");
            double paintPrice = json.getDouble("paintPrice");
            long batchId = json.getLong("batchId");
            double qtyVoucher = json.getDouble("qty");

            ServicePlanItem servicePlanItem = servicePlanItemRepository.findById(servicePlanItemId).orElseThrow(() -> new RuntimeException("未找到服务方案明细，编码为：" + servicePlanItemId));
            InventoryBatch batch = SpringManager.getBean(InventoryBatchRepository.class).findById(batchId).orElseThrow(() -> new RuntimeException("未找到批次信息，编码为：" + batchId));
            PartyRole supplier = SpringManager.getBean(PartyRoleRepository.class).findById(supplierId).orElseThrow(() -> new RuntimeException("未找到供应商，编码为：" + supplierId));

            servicePlanItem.addQtyVoucher(qtyVoucher);
            servicePlanItem.setInventoryBatch(batch);
            servicePlanItem.setSupplier(supplier);

            // 油漆商品单独处理
            if (VoucherType.PAINT_PRODUCT.equals(classification)) {
                servicePlanItem.setPaintFlag(true);
                servicePlanItem.setPaintPrice(paintPrice);
            }
            servicePlanItemRepository.save(servicePlanItem);

            // 判断是否有前置方案
            if (servicePlanItem.getParentServicePlanItem() == null) return;
            List<ServicePlanItem> list = servicePlanItemRepository.findAll(JpaDsl.toCriteriaByEq("id", servicePlanItem.getParentServicePlanItem().getId()));
            if (list.size() == 0 ) return;
            ServicePlanItem prePlanItem = list.stream().findFirst().get();

            //前置方案处理，如果是存在跨公司，就不回写供应商字段
            if (!prePlanItem.getServicePlan().getBelongDept().getCompany().getId().equals(servicePlanItem.getServicePlan().getBelongDept().getCompany().getId())) return;
            prePlanItem.addQtyVoucher(qtyVoucher);
            prePlanItem.setInventoryBatch(batch);
            prePlanItem.setSupplier(supplier);
            // 油漆商品单独处理
            if (VoucherType.PAINT_PRODUCT.equals(classification)) {
                prePlanItem.setPaintFlag(true);
                prePlanItem.setPaintPrice(paintPrice);
            }
            servicePlanItemRepository.save(prePlanItem);
        });

    }

    /**
     * 查找异业合作，相关方案
     * @param simpleRequest
     * @return
     */
    public Page<ServicePlan> findValidateSP(SimpleRequest simpleRequest){
        List<Map> fillters = simpleRequest.get("condition");
        fillters.add(MapUtil.mapper("field", "receivableDate", "value",null, "operator", "EQ"));
        fillters.add(MapUtil.mapper("field", "confirmDate", "value", null, "operator", "NE"));
        fillters.add(MapUtil.mapper("field", "state", "value", "termination", "operator", "NE"));
        Sort sort = new Sort(Sort.Direction.DESC, "createDate");
        Page page = servicePlanRepository.findAll(JpaDsl.toCriteria(fillters),PageRequest.of(simpleRequest.get("page"),simpleRequest.get("size"),sort));
        return page;
    }

    /**
     * 计算异业金额
     * @param req
     * @return
     */
    public Map calculateCrossIC(SimpleRequest req) throws Exception {
        JSONObject jo = req.getJO();
        boolean fnFlag = true; //默认单据公司和合作类型定义一致
        boolean matchFlag = false;
        CrossIC crossIC ;
        Dept belongDept;
        Product product;
//        double qtySal = 0;
        double pftPriceUnit = 0;
        try {
            product = SpringManager.getBean(ProductRepository.class).findOne(jo.getString("productID"));
            if(product == null || product.getClassify() == null) throw new RuntimeException("");
        }catch (Exception e){
            throw new RuntimeException("商品信息有误");
        }
        try {
            pftPriceUnit = jo.getDouble("pftUnit");
            if( pftPriceUnit <= 0) throw new Exception("");
        }catch (Exception e){
            throw new RuntimeException("未获取到该行的销售数量和单价");
        }
        try {
            crossIC=
                    SpringManager.getBean(CrossICRepository.class).findOne(jo.getString("crossID"));
            if(crossIC == null) throw new RuntimeException("");
        }catch (Exception e){
            throw new RuntimeException("异业合作类型有误");
        }
        try {
            belongDept = SpringManager.getBean(DeptRepository.class).findOne(jo.getString("belongID"));
            if(!belongDept.getCompany().getId().equals(crossIC.getCompany().getId())) fnFlag = false;
        }catch (Exception e){
            throw new RuntimeException("门店所属公司运营模式有误");
        }

        double deductionUnit = 0;
        double deductionAmount = 0;
        double selfSupportingUnit = 0;
        double selfSupportingAmount = 0;

        String city = null;
        try {
            city = SpringManager.getBean(StoreRepository.class).findOne(JpaDsl.toCriteriaByEq("dept.id",belongDept.getId())).get().getCity().getId();
        }catch (Exception e){
            throw new RuntimeException("营业门店地区设置有误，请检查设置");
        }


        //获取三个价格
        Object obj = this.invoke("condition.getCondition",MapUtil.mapper("conditionId","CROSS_CL","CROSS_SERVE",crossIC.getId(),"CITY",city,"SYS_RQ",new Date()));
        double priceCostUnitInTax = ((com.apestech.framework.json.JSONObject)obj).getDoubleValue("T001");
        double accountPrice = ((com.apestech.framework.json.JSONObject)obj).getDoubleValue("T002");
        double customerPrice = ((com.apestech.framework.json.JSONObject)obj).getDoubleValue("T003");


        if(priceCostUnitInTax == 0 && accountPrice == 0 && customerPrice == 0) throw new RuntimeException("无价格文件，请联系客服中心！");

        if(fnFlag){ //
            deductionUnit = priceCostUnitInTax;
        }else{
            deductionUnit = accountPrice;
        }
        if((crossIC.getProduct() != null && product.getId().equals(crossIC.getProduct().getId()))
                || (crossIC.getClassify() != null && product.getClassify().getId().startsWith(crossIC.getClassify().getId()))){ //所选异业合作类型中定义的商品或品类与方案商品一致时，顾客支付单价 取 合作类型定义里约定的顾客支付单价，该行销售单价 = （异业抵扣单价 + 顾客支付单价）

            matchFlag = true;
        }

        //计算金额
        deductionAmount = 0;
        selfSupportingAmount = 0;
        return MapUtil.mapper(
                "matchFlag",matchFlag,"crossPriceCost",priceCostUnitInTax,"crossAccountPrice",accountPrice,"crossCustomerPrice",customerPrice,
                "deductionUnit",deductionUnit,"deductionAmount",deductionAmount,
                "selfSupportingUnit",selfSupportingUnit,"selfSupportingAmount",selfSupportingAmount);
    }

    /**
     *
     * @param crossID
     * @param city
     * @return
     */
    public JSONObject getCL(String crossID,String city) throws Exception {
        //获取三个价格
        Object obj = this.invoke("condition.getCondition",MapUtil.mapper("conditionId","CROSS_CL","CROSS_SERVE",crossID,"CITY",city,"SYS_RQ",new Date()));
        double priceCostUnitInTax = ((com.apestech.framework.json.JSONObject)obj).getDoubleValue("T001");
        double accountPrice = ((com.apestech.framework.json.JSONObject)obj).getDoubleValue("T002");
        double customerPrice = ((com.apestech.framework.json.JSONObject)obj).getDoubleValue("T003");
        if(priceCostUnitInTax == 0 && accountPrice == 0 && customerPrice == 0) throw new RuntimeException("无价格文件，请联系客服中心！");
        return null;
    }

    /**
     * 异业合作操作
     * @param req
     * @return
     */
    public ServicePlan crossIC(SimpleRequest req){
        ServicePlan servicePlan = req.getO(ServicePlan.class);
        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {servicePlanItem.setRealPayAmount(servicePlanItem.getRealPayAmount());});
        //验证一些前端处理不正确数据
        checkData(servicePlan);


        //对兑换码 数量 异业单位进行一个验证
        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            if(servicePlanItem.getCrossIC() == null && servicePlanItem.getExchanceCodeList() != null && servicePlanItem.getExchanceCodeList().size() != 0)
                throw new RuntimeException("无异业合作单位，请清除兑换码，商品名称："+ servicePlanItem.getProduct().getName());
            if(servicePlanItem.getCrossIC() != null && (servicePlanItem.getExchanceCodeList() == null ||servicePlanItem.getExchanceCodeList().size() == 0))
                throw new RuntimeException("无兑换码，请清除异业合作单位，商品名称："+ servicePlanItem.getProduct().getName());
            //兑换商品数量为零
            if (servicePlanItem.getCrossIC() != null && servicePlanItem.getQtyExchanceAmount()==0.0)throw new RuntimeException("兑换商品数量为零，商品名称："+ servicePlanItem.getProduct().getName());
//            if(servicePlanItem.getCrossIC() != null && servicePlanItem.getExchanceCodeList().size() != 0 && servicePlanItem.getQtyExchanceCode() != servicePlanItem.getExchanceCodeList().size())
//                throw new RuntimeException("兑换码和数量不一致，请重新操作异业合作单位，商品名称："+ servicePlanItem.getProduct().getName());

            if(servicePlanItem.isUseCoupon() && servicePlanItem.getCrossIC() != null) throw new RuntimeException("使用了app优惠券，不能做异业项目，商品名称："+ servicePlanItem.getProduct().getName());
            if (servicePlanItem.getCrossIC()==null)servicePlanItem.setRealPayAmount(servicePlanItem.getSalesAmount());
        });
        servicePlan.computeSum();
        servicePlan = servicePlanRepository.saveAndFlush(servicePlan);
        JSONObject result = needPriceAudit(servicePlan,req);
        if(result.getBoolean("needPriceAudit")){
            this.invoke("fn.service.launchPriceAudit",MapUtil.mapped(servicePlan));
        }
        confirmToApp(servicePlan);
        return servicePlan;
    }





    /**
     * 验证是否能进行操作
     * @param servicePlan
     */
    private void checkData(ServicePlan servicePlan) {
        String bid = servicePlan.getBelongDept().getCompany().getId();
        servicePlan.getServicePlanItems().stream()
                .filter(servicePlanItem -> servicePlanItem.getCrossIC() != null)
                .forEach(servicePlanItem -> {
                    if ("02532952".equals(servicePlanItem.getCrossIC().getPartner().getId())) {
                        if (servicePlanItem.getExchanceCodeList() == null)
                            throw new RuntimeException("请输入正确的今日头条服务兑换码");
                        for (Object exchanceCode : servicePlanItem.getExchanceCodeList()) {
                            int length = String.valueOf(exchanceCode).toCharArray().length;
                            if (length != 12 && length != 19) throw new RuntimeException("请输入正确的今日头条服务兑换码");
                        }
                    }

                    CrossIC crossIC = servicePlanItem.getCrossIC();
                    String companyId = crossIC.getCompany().getId();
                    if (!(bid.equals(companyId) || "1001".equals(companyId)))
                        throw new RuntimeException("该异业抵扣不可选，请刷新后再做单！");
                    String crossId = crossIC.getCrossId();
                    this.invoke("mas.crossIC.checkDeptAuth", MapUtil.mapper("crossId", crossId, "deptId", servicePlan.getBelongDept().getId()));
                });
    }


    /**
     * 质检状态写凭证
     * @param servicePlan
     */
    public void createNXVoucher(ServicePlan servicePlan) {
        String id = servicePlan.getId();
        String deptId = servicePlan.getBelongDept().getId();
        List<Map> itemMaps = new ArrayList<>();
        if (servicePlan.isOldFrameQualityForVoucher()) { //判断是否是老框架质检，因为不存在内协多家门店，所以，不存在一部分新框架，一部分老框架门店情况
            itemMaps = servicePlan.getServicePlanItems().stream()
                    .filter(servicePlanItem ->
                            "ServicePlanItem.assistType.inner".equals(servicePlanItem.getAssistType().getId())
                                    && servicePlanItem.getOldFrameSourceFrom() != null
                                    && servicePlanItem.isSelected())
                    .map(servicePlanItem -> MapUtil.mapper("id", servicePlanItem.getId()))
                    .collect(Collectors.toList());

            if (itemMaps.size() != 0) { //找门店
                if (servicePlan.getSaleDept().getId().equals(servicePlan.getServiceDept().getId())) { //工单内协
                    List<MaintenanceOrder> mainList = maintenanceOrderRepository.findInnerMaintenanceOrder(
                            itemMaps.stream().map(item ->  item.get("id").toString()).collect(Collectors.toList()));
                    Map map = mainList.stream().collect(Collectors.groupingBy(maintenanceOrder -> maintenanceOrder.getInnerDept().getId()));
                    if (map.size() != 1) throw new RuntimeException("内协写凭证，找服务门店有误");
                    deptId = mainList.stream().findFirst().get().getInnerDept().getId();
                } else { //整单内协
                    deptId = servicePlan.getServiceDept().getId();
                }
            }
        } else if (!servicePlan.getBelongDept().getId().equals(servicePlan.getSaleDept().getId()) && "qualityTest".equals(servicePlan.getState())) { //基地方案，质检写凭证
            List<ServicePlanItem> servicePlanItems = servicePlan.getServicePlanItems().stream()
                    .filter(servicePlanItem -> servicePlanItem.getParentServicePlanItem() != null)
                    .map(ServicePlanItem::getParentServicePlanItem).collect(Collectors.toList());

            id = servicePlanItems.stream().findFirst().get().getServicePlan().getId();
            itemMaps = servicePlanItems.stream().map(servicePlanItem -> MapUtil.mapper("id", servicePlanItem.getId())).collect(Collectors.toList());
        }

        if (itemMaps.size() != 0) {
            this.invoke("retail.fnVoucherSaleOrder.createInnerHelpProcess", MapUtil.mapper("id", id, "serviceDeptId", deptId, "items", itemMaps));
        }
    }


    public ServicePlan updateServicePlanForMoney(ServicePlan servicePlan){
        servicePlan.computeSum();
        servicePlan.setUpdateDate(new Date());
        boolean write = servicePlan.isWrite();
        ServicePlan result = servicePlanRepository.saveAndFlush(servicePlan);
        result.setWrite(write);
        return result;
    }


    public ServicePlanItem findCBPForServicePlan(ServicePlanItem pServicePlanItem){
        List<ServicePlanItem> list = servicePlanItemRepository.findAll(JpaDsl.toCriteriaByEq("parentServicePlanItem.id",pServicePlanItem.getId(),"terminationDate",null));
        if(list.size() == 0) return null;
        if(list.size() > 1) throw new RuntimeException("找到多条子明细行，请检查程序");
        return list.stream().findFirst().get();
    }



    public void dealZZDJ(SimpleRequest req){
        JSONArray array = req.getJA();
        List<ServicePlan> list = servicePlanRepository.findTest(array);
        list.forEach(this::confirmToApp);
    }

    public void confirmToAppForButton(SimpleRequest req){
        JSONObject jo = req.getJO();
//        JSONArray array = req.getJA();
//        List<ServicePlan> list = servicePlanRepository.findTest(array);
        ServicePlan servicePlan = servicePlanRepository.findOne(jo.getString("id"));
        confirmToApp(servicePlan);
    }

    public ServicePlan updateClaimType(SimpleRequest req){
        JSONObject jo = req.getJO();
        String type = jo.getJSONObject("type").getString("id");
        BusinessAttributeValue attributeValue = SpringManager.getBean(BusinessAttributeValueRepository.class).findOne("LossQuotation.claimType."+type);
        if (attributeValue==null)
            throw new RuntimeException("无效类型");
        ServicePlan servicePlan = servicePlanRepository.findOne(jo.getString("id"));
        if ((!"LossQuotation".equals(servicePlan.getSourceBusinessType()))||servicePlan.getSourceFrom()==null)
            throw new RuntimeException("非定损来源单据");
        LossQuotation lossQuotation = lossQuotationRepository.findOne(servicePlan.getSourceFrom());
        if (lossQuotation==null)
            throw new RuntimeException("查询定损单据为空:"+servicePlan.getSourceFrom());
        lossQuotation.setClaimType(attributeValue);
        String carAccident = lossQuotation.getCarAccident();
        CarEvaluation evaluation = SpringManager.getBean(CarEvaluationRepository.class).findFirstByCarAccidentId(carAccident);
        if (evaluation==null)
            throw new RuntimeException("车险评估单不存在");
        evaluation.setClaimType(attributeValue);

        lossQuotationRepository.saveAndFlush(lossQuotation);

        CarEvaluation carEvaluation = SpringManager.getBean(CarEvaluationRepository.class).saveAndFlush(evaluation);
        confirmToApp(servicePlan);
        User adminUser = SpringManager.getBean(UserRepository.class).findOne(1);
        addServicePlanLogger(servicePlan,"修改理赔类型","修改理赔类型为:"+attributeValue.getName(),adminUser);
        assert lossQuotation != null;
        addServicePlanLogger(lossQuotation,"修改理赔类型","修改理赔类型为:"+attributeValue.getName(), adminUser);
        servicePlan.setWrite(false);
        return servicePlan;
    }

    /**
     * 传入明细行，获取内协情况
     * @param req
     * @return
     */
    public Map obtainInnerOuter(SimpleRequest req){
        JSONObject jo = req.getJO();
        String servicePlanItemId = jo.getString("servicePlanItemId");
        ServicePlanItem servicePlanItem = servicePlanItemRepository.findOne(servicePlanItemId);
        return MapUtil.mapper("servicePlanItemId",servicePlanItem.getId(),
                "servicePlanId",servicePlanItem.getServicePlan().getId(),
                "assistType",servicePlanItem.getAssistType().getId()
        );
    }

    /**
     * app终止车险优惠方案
     * @param
     * @return
     */
    public Map terminateServicePlanByInsurance(ServicePlan servicePlan){
        if (servicePlan.getInsuranceDiscounts() == null) throw new RuntimeException("该方案不是车险优惠方案");
        if (servicePlan.getQualityTestDate() != null) throw new RuntimeException("方案【" + servicePlan.getId() + "】已质检，如需调整，请先结算后退货");
        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            // if (servicePlanItem.getMaintenanceOrder().getWorkStartTime()!=null)throw new RuntimeException("方案【"+servicePlan.getId()+"】商品【"+servicePlanItem.getProduct().getId()+"-"+servicePlanItem.getProduct().getName()+"】已开始施工，需先终止");
            if (servicePlanItem.getQtyReceive() > 0)
                throw new RuntimeException("方案【" + servicePlan.getId() + "】商品【" + servicePlanItem.getProduct().getId() + "-" + servicePlanItem.getProduct().getName() + "】已领料，需先归还");
            servicePlanItem.setSelected(true);
            servicePlanItem.setQtyEndTemp(servicePlanItem.getSaleQty());
        });

        Map mapped = MapUtil.mapped(servicePlan);
        mapped.put("appFlage", true);
        return mapped;

    }

    /**
     * app终止服务方案
     * @param req
     * @return
     */
    public Map terminateServicePlan(SimpleRequest req){
        JSONObject jo = req.getJO();
        String servicePlanId = jo.getString("servicePlanId");
        PartyRole tRole = SpringManager.getBean(PartyRoleRepository.class).findOne(jo.getString("operator"));
        if (tRole == null) throw new RuntimeException("传入终止人员编码有误，人员编码：" + jo.getString("operator"));

        JSONArray items = jo.getJSONArray("items");
        ServicePlan servicePlan = servicePlanRepository.findOne(servicePlanId);
        if (servicePlan == null) throw new RuntimeException("该方案号未匹配到方案，请联系APP相关人员检查入参，方案号：" + servicePlanId);

        servicePlan.setOperator1(tRole);
        User user = SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id", servicePlan.getOperator1().getId())).stream().findFirst().orElse(null);
        servicePlan.setUserId(user == null ? null : String.valueOf(user.getId()));

        if (servicePlan.getInsuranceDiscounts() != null) return terminateServicePlanByInsurance(servicePlan);

        if (jo.getString("remake") != null) addServicePlanLogger(servicePlan, "APP终止方案", jo.getString("remake"));

        if (servicePlan.getConfirmDate() != null) {
            if (items == null || items.size() == 0) throw new RuntimeException("入参有无，明细行缺失");
            //数据校验
            items.forEach(tempJson -> {
                JSONObject item = (JSONObject) tempJson;
                ServicePlanItem servicePlanItemRe = servicePlan.getServicePlanItems().stream()
                        .filter(servicePlanItem -> item.getString("servicePlanItemId").equals(servicePlanItem.getId()))
                        .findFirst().orElse(null);
                if (servicePlanItemRe == null) throw new RuntimeException("该明细行编码未匹配到商品，请联系APP相关人员，明细行编码：" + item.getString("servicePlanItemId"));
            });

            //设置相关
            servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
                items.forEach(tempJson -> {
                    JSONObject item = (JSONObject) tempJson;
                    if (item.getString("servicePlanItemId").equals(servicePlanItem.getId())) {
                        servicePlanItem.setSelected(true);
                        servicePlanItem.setQtyEndTemp(item.getDouble("qtyEndTemp"));
                    }
                });
            });
        }
         return MapUtil.mapped(servicePlan);
    }

    /**
     * 停产下市商品，库存不够不允许做单
     * @param map
     */
    public void checkShutDownProduct(Map map) {
        //1.加入老框架编码
        JSONObject param = JSONObject.parseObject(new JSONObject(map).toJSONString());
        try {
            Dept dept = deptRepository.findOne(param.getString("NEW_DEPT_ID"));
            param.put("OLD_DEPT_ID",dept.getOrigin());
        }catch (Exception e){
            throw new RuntimeException("主数据设置有误，对应外部门店编码找不到");
        }
        if (param.getJSONArray("productList") == null || param.getJSONArray("productList").size() == 0) return;
        JSONArray array = servicePlanDao.queryProductStoreForList(param);

        List<String> errorList = param.getJSONArray("productList").stream().filter(outJsonTemp -> {
            JSONObject outJson = (JSONObject) outJsonTemp;
            return array == null || (array.stream().filter(item -> {
                JSONObject tempItem = (JSONObject) item;
                return outJson.getString("productId").equals(tempItem.getString("ID"))
                        && outJson.getDoubleValue("qty") > (tempItem.getDoubleValue("GENERAL_STOCK") + tempItem.getDoubleValue("SUB_STOCK") + tempItem.getDoubleValue("STOCK_AMOUNT"));
            }).count() != 0);
        }).map(outJsonTemp -> {
            JSONObject outJson = (JSONObject) outJsonTemp;
            outJson.putAll((JSONObject) array.stream().filter(item -> {
                JSONObject tempItem = (JSONObject) item;
                return tempItem.getString("ID").equals(outJson.getString("productId"));
            }).findFirst().get());
            double sum = outJson.getDoubleValue("GENERAL_STOCK") + outJson.getDoubleValue("SUB_STOCK") + outJson.getDoubleValue("STOCK_AMOUNT");
            return outJson.getString("productName") +":已停产下市，库存不足，最多可销售数量：" +  sum + ",门店库存："+ outJson.getDoubleValue("STOCK_AMOUNT")  + "，区域仓库存：" + outJson.getDoubleValue("SUB_STOCK") + "，总仓库存：" + outJson.getDoubleValue("GENERAL_STOCK");
        }).collect(Collectors.toList());

        if(errorList.size() != 0){
            String error = "";
            for(int i = 0;i<errorList.size();i++){
                if(i == 0){
                    error = errorList.get(i);
                }else{
                    error = error + ";" + errorList.get(i);
                }
            }
            throw new RuntimeException(error);
        }
    }


    /**
     * {
     *     "id":"要货单主标编码",
     *     "productRequireItems":[
     *         {
     *             "product_id":"商品明细行编码",
     *             "qtyEnd":"终止数量",
     *             "remark":"备注"
     *         }
     *     ]
     * }
     * 完成询价
     * @return
     */
/*    @OutboxSubscriber(id="servicePlan.server.repealProductRequire", name="方案终止终止要货")
    public void repealProductRequire(OutboxPayloadWrapper wrapper){
        JSONObject tempJson = JSON.parseObject(wrapper.getPayload());
        this.invoke("stock.productRequire.repeal",tempJson);
    }*/


/*
    public void endQuire(SimpleRequest req){
        ServicePlan servicePlan = servicePlanRepository.findOne(req.getJO().getString("id"));     //根据方案号检测是否有对应的要货单，如果有的话，
        List<ProductRequire> productRequires =
                SpringManager.getBean(ProductRequireRepository.class).findAll(JpaDsl.toCriteriaByEq("source", servicePlan.getId(), "sourceBusinessType", "servicePlan","approveDate",null));

        if (productRequires != null || productRequires.size() != 0) {
            Map<String, List<ServicePlanItem>> mapItems = servicePlan.getServicePlanItems().stream().filter(servicePlanItem -> {
                return servicePlanItem.getQtyEnd() > 0;
            }).collect(Collectors.groupingBy(servicePlanItem -> servicePlanItem.getProduct().getId()));

            productRequires.stream().forEach(productRequire -> {
                List<Map> productRequireItemMaps = productRequire.getProductRequireItems().stream().filter(productRequireItem -> {
                    //当前商品，过滤可终止数量小于等于0的要货明细
                    return productRequireItem.canEndQty() > 0 && mapItems.containsKey(productRequireItem.getProduct().getId());
                }).map(productRequireItem -> {
                    double mQty = mapItems.get(productRequireItem.getProduct().getId()).stream().mapToDouble(serviceplanitem -> {
                        return serviceplanitem.getQtyEnd();
                    }).sum();
                    return MapUtil.mapper("product_id", productRequireItem.getProduct().getId(),
                            "remark", "门店终止方案导致要货单终止",
                            "qtyEnd", mQty >= productRequireItem.canEndQty() ?  productRequireItem.canEndQty() : mQty );
                }).collect(Collectors.toList());
                try {
                    this.invoke("stock.productRequire.repeal", productRequire*//*MapUtil.mapper("id",productRequire.getId(),"productRequireItems",productRequireItemMaps)*//*);
                }catch (Exception e){
                    throw new RuntimeException(e.getMessage() + "入参：【"+MapUtil.mapper("id",productRequire.getId(),"productRequireItems",productRequireItemMaps).toString()+"】");
                }
            });
        }

    }*/


    /**
     *同步工单
     * @param simpleRequest
     * @return
     */
    public List synServiceplanForTimestamp(SimpleRequest simpleRequest){
        JSONObject jsonObject = simpleRequest.getJO();
        String id = jsonObject.getString("id");
        int maxNum = jsonObject.getInteger("maxNum");
        Date date = new Date(jsonObject.getLong("timestamp"));
        if(maxNum > 100)  throw new RuntimeException("页数据不能大于500");
        List<ServicePlan> list = servicePlanRepository.synServiceplanForTimestamp(date, id, PageRequest.of(0, maxNum));

        return list.stream().map(servicePlan -> {
            return MapUtil.mapper(
                    "id",servicePlan.getId(),
                    "createDate", servicePlan.getCreateDate(),
                    "creator",servicePlan.getCreator(),
                    "sourceFrom",servicePlan.getSourceFrom(),
                    "sourceBusinessType",servicePlan.getSourceBusinessType(),
                    "sourceBusinessTypeName",servicePlan.getSourceBusinessTypeName(),
                    "state",servicePlan.getState(),
                    "serviceDept",servicePlan.getServiceDept().getId(),
                    "fnCustomerExpand",servicePlan.getFnCustomerExpand() == null ? null : MapUtil.mapper("carLicense", servicePlan.getFnCustomerExpand().getCarLicense(),"userId",servicePlan.getFnCustomerExpand().getUserId()),
                    "company",servicePlan.getCompany().getId(),
                    "belongDept",servicePlan.getBelongDept().getId(),
                    "saleDept",servicePlan.getSaleDept().getId(),
                    "submissionDate", servicePlan.getSubmissionDate(),
                    "submissionUid",servicePlan.getSubmissionUid() == null ? null : servicePlan.getSubmissionUid().getId(),
                    "confirmDate",servicePlan.getConfirmDate(),
                    "confirmUid",servicePlan.getConfirmUid() == null ? null : servicePlan.getConfirmUid().getId(),
                    "qualityTestDate",servicePlan.getQualityTestDate(),
                    "receivableDate",servicePlan.getReceivableDate(),
                    "terminationUid",servicePlan.getTerminationUid() == null ? null :servicePlan.getTerminationUid().getId(),
                    "terminationDate",servicePlan.getTerminationDate(),
                    "remark", servicePlan.getDeptRemark(),
                    "lastUpdatedStamp",servicePlan.getLastUpdatedStamp(),
                    "servicePlanItems",servicePlan.getServicePlanItems().stream().map(servicePlanItem -> {
                        return MapUtil.mapper(
                                "id",servicePlanItem.getId(),
                                "lastUpdatedStamp",servicePlanItem.getLastUpdatedStamp(),
                                "serviceState",servicePlanItem.isServiceState(),
                                "primaryPriceUnit",servicePlanItem.getPrimaryPriceUnit(),
                                "salesAmount",servicePlanItem.getSalesAmount(),
                                "clerkPriceLimit",servicePlanItem.getClerkPriceLimit(),
                                "shopOwnerPriceLimit",servicePlanItem.getShopOwnerPriceLimit(),
                                "csoPriceLimit",servicePlanItem.getCsoPriceLimit(),
                                "basePrice",servicePlanItem.getBasePrice(),
                                "discountRate",servicePlanItem.getDiscountRate(),
                                "platformPriceCosInTax",servicePlanItem.getPlatformPriceCosInTax(),
                                "priceCostUnitInTax",servicePlanItem.getPriceCostUnitInTax(),
                                "estimatedCommission",servicePlanItem.getEstimatedCommission(),
                                "product",MapUtil.mapper("id",servicePlanItem.getProduct().getId(),"name",servicePlanItem.getProduct().getName(),"classify",servicePlanItem.getProduct().getClassify()),
                                "pftPriceUnit",servicePlanItem.getPftPriceUnit(),
                                "priceUnit",servicePlanItem.getPriceUnit(),
                                "floorPrice",servicePlanItem.getFloorPrice(),
                                "saleQty",servicePlanItem.getSaleQty(),
                                "qtyReceive",servicePlanItem.getQtyReceive(),
                                "qtyEnd",servicePlanItem.getQtyEnd(),
                                "uom",MapUtil.mapper("name",servicePlanItem.getUom().getName()),
                                "assistType",MapUtil.mapper("code",servicePlanItem.getAssistType() == null ? null :servicePlanItem.getAssistType().getCode(),"name",servicePlanItem.getAssistType() == null ? null :servicePlanItem.getAssistType().getName())
                        );
                    }).collect(Collectors.toList())
            );
        }).collect(Collectors.toList());
    }

    @OutboxSubscriber(name = "APP要求，方案改变发信号量给APP")
    public void sentSinalToAppForServiceplan(ServicePlan serviceplan){
        this.invoke("pi.app.ext", MapUtil.mapper("headers",MapUtil.mapper("method","v1/yyerp-sync/notify","action","post"),"body",
                MapUtil.mapper("yyerpApiName","fn.service.synServiceplanForTimestamp","timestamp",serviceplan.getLastUpdatedStamp())));
    }



    @Listener(topic = "event:pi.epc.synEpcNotify")
    public boolean  synEpcNotify(SimpleRequest request){
        Map map = request.getMap();
        String deptId = (String)(map.get("deptId"));
        EpcDeptSet epcDeptSet =  SpringManager.getBean(EpcDeptSetRepository.class).findOne(deptId);
        if(epcDeptSet == null){
            return false;
        }else{
            return true;
        }
    }

    /**
     * 目的： 重新给方案排序，返回前端。
     * @param request
     * @return
     */
    public ServicePlan sortFotErp(SimpleRequest request){
        ServicePlan servicePlan = request.getO(ServicePlan.class);
        if(servicePlan.getServicePlanItems().size() == 0) return null;
        return getCurrentTimeData(findCarServiceLevel(servicePlan));
    }

    public Map waitReceiveList(SimpleRequest re){
        String deptId = re.getJO().getString("deptId");
        JSONObject jo = new JSONObject();
        jo.put("DEPTID",deptId);
        JSONArray array= servicePlanDao.waitReceiveList(jo);

        List listOne = new ArrayList(); //待领料车辆
        List listTwo = new ArrayList(); //已领料车辆

        array.stream().collect(groupingBy(item ->{
            JSONObject tempJson = (JSONObject)item;
            return tempJson.getString("CAR_LICENSE");
        })).forEach((k,v)->{
            JSONArray  vArray = new JSONArray(v);
            JSONObject map  = new JSONObject();
            map.put("CAR_LICENSE",vArray.getJSONObject(0).getString("CAR_LICENSE"));
            map.put("fnCustomerExpand",vArray.getJSONObject(0).getString("FNCUSTOMEREXPAND"));
            map.put("REALNAME",vArray.getJSONObject(0).getString("REALNAME"));
            map.put("CAR_MODEL_LABEL",vArray.getJSONObject(0).getString("CAR_MODEL_LABEL"));
            map.put("JEKUN_MODEL_CODE",vArray.getJSONObject(0).getString("JEKUN_MODEL_CODE"));
            map.put("PICK_TIME",vArray.getJSONObject(0).getDate("PICK_TIME"));

            int amount = (int) array.stream().filter(itemJ -> {
                JSONObject itemJTemp = (JSONObject) itemJ;
                return k.equals(itemJTemp.getString("CAR_LICENSE")) && (itemJTemp.getDoubleValue("SALE_QTY") - itemJTemp.getDoubleValue("QTY_END") != itemJTemp.getDoubleValue("QTY_RECEIVE"));
            }).count();
            if(amount == 0){ //材料已全部领用
                map.put("TIP","已领");
                map.put("QTY",vArray.size());
                listTwo.add(map);
            }else{
                map.put("TIP","待领料");
                map.put("QTY",amount);
                listOne.add(map);
            }
        });


        array.stream().filter(item ->{
            return ((JSONObject)item).get("ESTIMATED_DELIVERY_DATE") != null;
        }).collect(groupingBy(item ->{
            JSONObject tempJson = (JSONObject)item;
            return tempJson.getString("CAR_LICENSE");
        })).forEach((k,v)->{
            JSONArray vArray = new JSONArray(v);

            JSONObject maxJson = (JSONObject) vArray.stream().max((a, b)->{
                return ((JSONObject)a).getDate("ESTIMATED_DELIVERY_DATE").getTime() >=  ((JSONObject)b).getDate("ESTIMATED_DELIVERY_DATE").getTime() ?  1 : -1 ;
            }).get();

            listOne.forEach(item ->{
                JSONObject json = (JSONObject)item;

                if(k.equals(json.getString("CAR_LICENSE"))){
                    json.put("ESTIMATED_DELIVERY_DATE",maxJson.getString("ESTIMATED_DELIVERY_DATE"));
                }

            });
            listTwo.forEach(item ->{
                JSONObject json = (JSONObject)item;
                if(k.equals(json.getString("CAR_LICENSE"))){
                    json.put("ESTIMATED_DELIVERY_DATE",maxJson.getString("ESTIMATED_DELIVERY_DATE"));
                }
            });

        });


        return MapUtil.mapper("waitReceiveQty",listOne.size(),"waitReceive",sortListByJson(listOne),"received",sortListByJson(listTwo));
    }

    public Map receiveList(SimpleRequest re){
        JSONObject jo = new JSONObject();
        jo.put("DEPTID",re.getJO().getString("deptId"));
        jo.put("FNCUSEXPANDID",re.getJO().getString("fnCustomerExpand"));
        JSONArray array = servicePlanDao.receiveList(jo);
        List reList = new ArrayList();
        if(array.size() == 0){
            array = servicePlanDao.receiveListCarInfo(jo);
            if(array.size() == 0) throw new RuntimeException("页面失效，请重新刷新界面");
        }else{
            //查询是否转工单信息
            JSONArray orderArray = servicePlanDao.receiveListFindOrder(jo);

            array.stream().collect(groupingBy(item ->{
                JSONObject tempJson = (JSONObject)item;
                return tempJson.getString("SERVICEPLAN_ID");
            })).forEach((k,v)->{
                JSONArray vArray = new JSONArray(v);

                List list = orderArray.stream().filter(orderItem -> k.equals(((JSONObject)orderItem).getString("SERVICEPALN_ID")))
                        .collect(Collectors.toList());

                JSONObject json = new JSONObject();
                json.put("haveOrder", list.size() == 0);
                json.put("SERVICEPLAN_ID",k);
                json.put("STATE",vArray.getJSONObject(0).getString("STATE"));
                json.put("CONFIRM_DATE",vArray.getJSONObject(0).getDate("CONFIRM_DATE"));
                json.put("productList",vArray.stream().map(item ->{
                    JSONObject vJson = (JSONObject)item;
                    return MapUtil.mapper(
                            "SERVICEPLAN_ID",vJson.getString("SERVICEPLAN_ID"),
                            "SERVICEPLAN_ITEM_ID",vJson.getString("SERVICEPLAN_ITEM_ID"),
                            "PRODUCT_ID",vJson.getString("PRODUCT_ID"),
                            "PRODUCT_NAME",vJson.getString("PRODUCT_NAME"),
                            "BARCODE",vJson.getString("BARCODE"),
                            "LOCATION_ID",vJson.getString("LOCATION_ID"),
                            "LOCATION_NAME",vJson.getString("LOCATION_NAME"),
                            "SALE_QTY",vJson.getDoubleValue("SALE_QTY") - vJson.getDoubleValue("QTY_END"),
                            "QTY_RECEIVE",vJson.getDoubleValue("QTY_RECEIVE"),
                            "QTY_STOCK",vJson.getDoubleValue("QTY_STOCK"),
                            "UOM_ID",vJson.getString("UOM_ID"),
                            "UOM_NAME",vJson.getString("UOM_NAME"),
                            "isReceived", vJson.getDoubleValue("QTY_RECEIVE") == vJson.getDoubleValue("SALE_QTY") - vJson.getDoubleValue("QTY_END")
                    );
                }).collect(Collectors.toList()));
                reList.add(json);
            });

        }
        JSONObject firstJson = array.getJSONObject(0);

        Collections.sort(reList, (Comparator<JSONObject>) (o1, o2) -> o1.getDate("CONFIRM_DATE").getTime() < o2.getDate("CONFIRM_DATE").getTime() ? -1 : 1);
        return MapUtil.mapper("CAR_LICENSE",firstJson.getString("CAR_LICENSE"),
                "CAR_MODEL_LABEL",firstJson.getString("CAR_MODEL_LABEL"),
                "JEKUN_MODEL_CODE",firstJson.getString("JEKUN_MODEL_CODE"),
                "productSize",array.size(),
                "ITEMS",reList
                );
    }

    public Map receiveListFinishWork(SimpleRequest re){
        JSONObject jo = new JSONObject();
        jo.put("RELEVANCE_WORK_ORDER",re.getJO().getString("RELEVANCE_WORK_ORDER"));
        JSONArray array = servicePlanDao.receiveListFinishWork(jo);

        List reList = new ArrayList();
        if(array.size() != 0){
            reList = array.stream().map(item ->{
                JSONObject vJson = (JSONObject)item;
                return MapUtil.mapper(
                        "SERVICEPLAN_ID",vJson.getString("SERVICEPLAN_ID"),
                        "SERVICEPLAN_ITEM_ID",vJson.getString("PRODUCT_ID"),
                        "PRODUCT_ID",vJson.getString("PRODUCT_ID"),
                        "PRODUCT_NAME",vJson.getString("PRODUCT_NAME"),
                        "BARCODE",vJson.getString("BARCODE"),
                        "LOCATION_ID",vJson.getString("LOCATION_ID"),
                        "LOCATION_NAME",vJson.getString("LOCATION_NAME"),
                        "SALE_QTY",vJson.getDoubleValue("SALE_QTY") - vJson.getDoubleValue("QTY_END"),
                        "QTY_RECEIVE",vJson.getDoubleValue("QTY_RECEIVE"),
                        "QTY_STOCK",vJson.getDoubleValue("QTY_STOCK"),
                        "isReceived", vJson.getDoubleValue("QTY_RECEIVE") == vJson.getDoubleValue("SALE_QTY") - vJson.getDoubleValue("QTY_END")
                );
            }).collect(Collectors.toList());

        }
        return MapUtil.mapper("ID",re.getJO().getString("RELEVANCE_WORK_ORDER"),"items",reList);
    }

    private List sortListByJson(List list){
        Collections.sort(list, (Comparator<JSONObject>) (o1, o2) -> o1.getDate("PICK_TIME") == null ? -1 :
                o2.getDate("PICK_TIME") ==  null ? 1 :
                        o1.getDate("PICK_TIME").getTime() < o2.getDate("PICK_TIME").getTime() ? -1 : 1);
        return list;
    }

    public List<ServicePlan> findServicePlansForPDA(List<String> deptIds){
        JSONObject param = new JSONObject();
        param.put("deptId", deptIds);
        JSONArray array = servicePlanDao.findServicePlansForPDA(param);
        if (array.size() == 0) return new ArrayList<>();

        List list = array.stream().map(item->((JSONObject)item).getString("ID")).collect(Collectors.toList());
        return servicePlanRepository.findPlanForReceive(list);
    }


    /**
     * 方案整单终止，方案质检完成调用：终止尚未审核的领用单
     * 触发点：方案完成终止，方案完整质检触发
     * @param
     */
    private void deletePRByPlanEnd(ServicePlan servicePlan){ //g
        if(!("termination".equals(servicePlan.getState()) || "qualityTest".equals(servicePlan.getState()))) return ; //如果传入的方案非终止或者质检状态，则不做处理
        List<ProductReceive> productReceives= productReceiveRepository
                .findEndOrderByPlanItems(servicePlan.getServicePlanItems().stream()
                .map(ServicePlanItem::getId).collect(Collectors.toList()));
        if(productReceives.size()!= 0){
            OutboxPayloadWrapper wrapper = new OutboxPayloadWrapper();
            wrapper.setSubscriber("pr.delete.deleteByPlanEnd");
            wrapper.setPayload(
                    JSON.toJSONString(productReceives.stream().map(ProductReceive::getId).collect(Collectors.toList()))
            );
            wrapper.setAggregateId(servicePlan.getId());
            SpringManager.getBean(OutboxEventService.class).sendSaveEvent(wrapper);
        }
    }

    public ServicePlan copy(SimpleRequest request){
        JSONObject jo = request.getJO();
        ServicePlan oldServicePlan = servicePlanRepository.findOne(jo.getString("ID"));
        if (!"termination".equals(oldServicePlan.getState()))throw new RuntimeException("当前方案不为终止状态");
        if ("定损报价单".equals(oldServicePlan.getSourceBusinessTypeName()))throw new RuntimeException("定损报价单来源不能补单");
        if (!oldServicePlan.getPlanType().equals("common"))throw new RuntimeException("内协方案不能补单");
        if (oldServicePlan.getOldFrameSourceFrom()!=null)throw new RuntimeException("老框架来源不能补单");
        ServicePlan servicePlan = servicePlanRepository.findOneBySourceFromOrderByCreateDateDesc(oldServicePlan.getId()).stream().findFirst().orElse(oldServicePlan);
        Date createDate = servicePlan.getCreateDate();
        if (new Date(createDate.getTime()+(1000*60)).after(new Date()))throw new RuntimeException("该方案一分钟内已经进行过补单,单号为:"+servicePlan.getId()+",请勿频繁补单.");

        ServicePlan newPlan = new ServicePlanBuilder(request)
                .setCarLicense(oldServicePlan.getFnCustomerExpand().getCarLicense())
                .setState("create")
                .setNote(oldServicePlan.getId(), "copy", "补单")
                .setItems(oldServicePlan.getServicePlanItems().stream().map(servicePlanItem ->new JSONObject(Objects.requireNonNull(MapUtil.mapped(servicePlanItem)))).collect(Collectors.toList()))
                .fastBuildServicePlan();
        return getCurrentTimeData(newPlan);

    }

	/** 提交终止供应商询价单 */
    public void submitSynGYSXJD(String id) {
        JSONObject data = new JSONObject();
        data.put("LYDJHM", id);
        outboxSubscriberService.commonSendRequest("local:servicePlanceService.submitSynGYSXJDPi", "subimitSynGYSXJD: " + id, data);
    }

    @OutboxSubscriber(id="local:servicePlanceService.submitSynGYSXJDPi", name="提交终止供应商询价单")
    private void submitSynGYSXJDPi(OutboxPayloadWrapper outboxPayloadWrapper) {
        piManager.synErp("autoZZDJService.exec_ZZGYSXJD_XKJ", outboxPayloadWrapper.getPayload());
    }

    /**
     * 询价池导入方案
     * @param request
     * @return GetPriceLoggerInquiryExtend
     */
    public JSONArray getInquiryPoolItem(SimpleRequest request){
        JSONArray result ;
        JSONObject servicePlan = request.getJO();
        JSONArray inquiryGoodsArray = servicePlan.getJSONArray("PUR_SPXJDMX");
        if (servicePlan.getString("orderTypeTemp")==null&&servicePlan.getString("id")==null)throw new RuntimeException("未知单据");
        boolean isLoss = (servicePlan.getString("orderTypeTemp") != null && !servicePlan.getString("orderTypeTemp").contains("服务方案")) ||
                (servicePlan.getString("id") != null && servicePlan.getString("id").startsWith("DS"));
        if (isLoss){
                //定损入口
             result = this.invoke("fn.lossQuotation.getInquiryPoolItem", servicePlan);
        }else {
            inquiryGoodsArray.forEach(item ->{
                JSONObject itemTemp = (JSONObject)item;
                itemTemp.put("GSID",itemTemp.getString("GSID"));
                itemTemp.put("PTID",itemTemp.getString("PTID"));
            });
            result = translateField(inquiryGoodsArray, servicePlan);
        }
        getPriceLoggerService.addInquiryExtendDetail(servicePlan,result,isLoss);
        return result;
    }

    public JSONArray translateField(JSONArray inquiryGoodsArray,JSONObject servicePlan){
        JSONArray jgArray = new JSONArray();
        //获取定价过程
        jgArray = makePrices(jgArray,servicePlan,inquiryGoodsArray);

        for(int i = 0 ;i< inquiryGoodsArray.size();i++){
            boolean flag = true;
            JSONObject item1 = inquiryGoodsArray.getJSONObject(i);
            for(int j = 0; j < jgArray.size() ;j ++){
                JSONObject item2 = jgArray.getJSONObject(j);
                if(item1.getString("uniqueIdentify").equals(item2.getString("uniqueIdentify"))){
                    flag = false;
                    item1.putAll(item2);
                }
            }
            if(flag) throw new RuntimeException("询价未匹配到价格，请联系处理");
        }
        //库区额外信息
        JSONArray resultList = new JSONArray();
        //设置价格
        inquiryGoodsArray.forEach((item) -> resultList.add(setPriceForWeb(new JSONObject(),item,servicePlan)));
        return resultList;

    }

    /**
     * 获取定价过程
     * @param resultArray
     * @param servicePlan
     * @param inquiryGoodsArray
     * @return
     */
    public JSONArray makePrices(JSONArray resultArray,JSONObject servicePlan,JSONArray inquiryGoodsArray){
        Dept belongDept = deptRepository.findOne(servicePlan.getJSONObject("belongDept").getString("id"));
        String saleID = servicePlan.getJSONObject("saleDept").getString("id");
        if(servicePlan.getJSONObject("serveType")!=null&&servicePlan.getJSONObject("serveType").getString("id").equals("ServicePlan.serveType.B")){
            saleID=servicePlan.getJSONObject("belongDept").getString("id");
        }
        Dept saleDept = deptRepository.findOne(saleID);

        JSONObject fnCustomerExpand = servicePlan.getJSONObject("fnCustomerExpandTemp");
        JSONObject customer = fnCustomerExpand.getJSONObject("customer");
        if(!belongDept.getId().equals(saleDept.getId())){  //GS51 if(!this.belongDept.getId().equals(this.saleDept.getId())) return true;
            List<Map> listMap= inquiryGoodsArray.stream().map((tempJson1)->{
                JSONObject item = (JSONObject)tempJson1;
                Product product = findProductById(item.getString("SPID"));
                item.put("uniqueIdentify",item.getString("XJDH") + item.getString("SPID"));
                return MapUtil.mapper(
                        "uniqueIdentify",item.getString("uniqueIdentify"),
                        "SPID",product.getId(),
                        "PLID",product.getClassify().getId(),
                        "PZID",product.getBrand().getQuality() == null ? null : product.getBrand().getQuality().getCode(),
                        "GSID",belongDept.getCompany().getId(),
                        "YYMS",belongDept.getCompany().getParty().getCorporate().getOperation().getCode(),
                        "NYYMS",belongDept.getCompany().getParty().getCorporate().getOperation().getId(),
                        "KHID",SpringManager.getBean(PartyRoleService.class)
                                .findByPartyAndRole(belongDept.getCompany().getParty().getId(), "Customer").getId(),
                        "CGZZID",item.getString("CGZZID"),
                        "JLDW",item.getString("JLDW"),
                        "JLDWID", product.getUom().getId(),
                        "JRS",fnCustomerExpand.get("vendorCode"),
                        "SYGSID",item.getString("PTID"),
                        "JCGSID",saleDept.getCompany().getId(),
                        "CPHM",fnCustomerExpand.get("carLicense"),
                        "XJDH",item.getString("XJDH"),
                        "CLFWDJID",((CarServiceLevel)(SpringManager.getBean(CarServiceLevelService.class).findByCarConfigurationId(fnCustomerExpand.getString("jekunModelCode")))).getId(),
                        "XSDJ",item.getDouble("XSDJ"),
                        "XSXJ",item.getDouble("XSXJ"),
                        "P001",item.getDouble("CGDJ")

                );
            }).collect(Collectors.toCollection(ArrayList::new));
            resultArray = serviceToForeign.getGS51(listMap);

        }else{ //XJ51
            List<Map> listMap= inquiryGoodsArray.stream().map((tempJson1)->{
                JSONObject item = (JSONObject)tempJson1;
                Product product = findProductById(item.getString("SPID"));
                item.put("uniqueIdentify",item.getString("XJDH") + item.getString("SPID") );
                return MapUtil.mapper(
                        "uniqueIdentify",item.getString("uniqueIdentify"),
                        "GSID",belongDept.getCompany().getId(),
                        "SYGSID",item.getString("PTID"),
                        "XYGSID",belongDept.getCompany().getId(),
                        "MDID",belongDept.getId(),
                        "PLID",product.getClassify().getId(),
                        "SPID",product.getId(),
                        "JRS",customer.getString("vendorCode"),
                        "PZID",product.getBrand().getQuality() == null ? null : product.getBrand().getQuality().getCode(),
                        "YYMS",belongDept.getCompany().getParty().getCorporate().getOperation().getCode(),
                        "NYYMS",belongDept.getCompany().getParty().getCorporate().getOperation().getId(),
                        "FNVIPJBID", customer.getString("level"),
                        "FNVIPSFID",customer.getJSONObject("userRole")!=null?customer.getJSONObject("userRole").getString("id"):null,
                        "FNKHID",customer.getJSONObject("unitClient")!=null?customer.getJSONObject("unitClient").getString("clientCode"):null,
                        "JLDW",item.getString("JLDW"),
                        "XSDJ",item.getDouble("XSDJ"),
                        "XSXJ",item.getDouble("XSXJ"),
                        "P001",item.getDouble("CGDJ")
                );
            }).collect(Collectors.toCollection(ArrayList::new));
            resultArray = serviceToForeign.getXJ51(listMap);
            resultArray=resultArray.stream().map(v -> {
            JSONObject result = new JSONObject((Map)v);
            inquiryGoodsArray.forEach(item -> {
                JSONObject inquiryGood = new JSONObject((Map)item);
                if (result.getString("uniqueIdentify").equals(inquiryGood.getString("XJDH") + inquiryGood.getString("SPID"))) {
                    result.putAll(inquiryGood);
                    result.put("platformPriceCosInTax", inquiryGood.getDouble("CGDJ"));
                    result.put("priceCostUnitExTax", inquiryGood.getDouble("CGDJ"));
                    result.put("priceCostUnitInTax", inquiryGood.getDouble("CGDJ"));
                    result.put("floorPrice", inquiryGood.getDouble("XSXJ"));
                    result.put("supplyChainManagement", result.getDoubleValue("supplyRate") * inquiryGood.getDouble("CGDJ"));
                    result.put("referTax", result.getDoubleValue("referTax") == 0 ? (1 + result.getDoubleValue("supplyRate")) * inquiryGood.getDouble("CGDJ") : result.getDoubleValue("referTax"));
                }
            });
            return result;
        }).collect(Collectors.toCollection(JSONArray::new));
        }
        return resultArray;
    }

    /**
     * 设置价格参数 返回前端
     * @param resultJson 返回结果集
     * @param item  商品明细
     * @param servicePlan
     * @return
     */
    public JSONObject setPriceForWeb(JSONObject resultJson,Object item,JSONObject servicePlan){
        Dept belongDept = deptRepository.findOne(servicePlan.getJSONObject("belongDept").getString("id"));
        JSONObject quiryJson = (JSONObject) item;
        resultJson.put("company", belongDept.getCompany());
        resultJson.put("state", "create");
        PartyRole partyRole = SpringManager.getBean(PartyRoleService.class).findOne(quiryJson.getString("PTID"),"Company");
        resultJson.put("platform", partyRole);
        //商品
        String spmc = quiryJson.getString("SPMC").replace("\"","\\\"");
//        resultJson.put("product", JSONObject.parseObject("{" +
//                "\"id\":\""+quiryJson.getString("SPID")+"\"," +
//                "\"name\":\""+ spmc +"\"}" ));
        resultJson.put("category", JSONObject.parseObject("{" +
                "\"id\":\""+quiryJson.getString("PJMCID")+"\"," +
                "\"name\":\""+quiryJson.getString("PJMC")+"\"}" ));
        List<ProductUom> productUomList = productUomRepository.findAll(
                JpaDsl.toCriteriaByEq("uomCategory.id", quiryJson.getString("SPID"), "name", quiryJson.getString("JLDW")));
        if (productUomList==null||productUomList.size()==0)throw new RuntimeException("该商品未定义计量单位，计量单位"+ quiryJson.getString("JLDW") + ",对应商品：" + quiryJson.getString("SPID"));
        if (productUomList != null && productUomList.size() != 0) {
            resultJson.put("uom", productUomList.get(0));
        }

        //价格
        resultJson.put("primaryPriceUnit",quiryJson.getDoubleValue("primaryPriceUnit"));
        resultJson.put("primaryPriceUnitShow", quiryJson.getDoubleValue("primaryPriceUnit"));
        resultJson.put("uniqueValue", quiryJson.getString("WYZ"));
        resultJson.put("priceUnit", quiryJson.getDoubleValue("priceUnit"));
        resultJson.put("pftPriceUnit", quiryJson.getDoubleValue("pftPriceUnit"));
        resultJson.put("managementFeeRate", quiryJson.getDouble("managementFeeRate"));
        resultJson.put("floorPrice", quiryJson.getDoubleValue("floorPrice"));
        resultJson.put("clerkPriceLimit", quiryJson.getDouble("clerkPriceLimit"));
        resultJson.put("shopOwnerPriceLimit", quiryJson.getDouble("shopOwnerPriceLimit"));
        resultJson.put("inquirySource","inquiry");
        resultJson.put("csoPriceLimit", quiryJson.getDouble("csoPriceLimit"));
        resultJson.put("basePrice", quiryJson.getDouble("basePrice"));
        resultJson.put("priceSource", quiryJson.getString("priceSource"));
        resultJson.put("outSupplier", quiryJson.getString("SUPPLIER_ID"));
        resultJson.put("discountRate", quiryJson.getDoubleValue("discountRate"));
        resultJson.put("priceCostUnitInTax", quiryJson.getDoubleValue("priceCostUnitInTax"));
        resultJson.put("priceCostUnitExTax", quiryJson.getDoubleValue("priceCostUnitExTax"));
        resultJson.put("platformPriceCosInTax", quiryJson.getDoubleValue("platformPriceCosInTax"));
        resultJson.put("referTax", quiryJson.getDoubleValue("pftPriceUnit") <= 0 ? 0 : quiryJson.getDoubleValue("referTax"));

        Product product = productRepository.findOne(quiryJson.getString("SPID"));
        if (Objects.isNull(product)) {
            throw new RuntimeException("系统中未找到该商品数据,编码: " + quiryJson.getString("SPID"));
        }
        resultJson.put("product", product);

        if (!StringUtils.isEmpty(quiryJson.get("GYSID"))) {
            String gysid = quiryJson.getString("GYSID");
            gysid = gysid.length() == 8?gysid.substring(2, gysid.length()):gysid;
            PartyRole supplier = getBean(PartyRoleRepository.class).findOne(gysid);
            resultJson.put("supplier", supplier);
        }
        double fee = SpringManager.getBean(FeeRateService.class).getSupplyChainManagementFee(belongDept.getCompany().getId(), product.getClassify().getId(), "");
        resultJson.put("supplyChainManagement", quiryJson.getDoubleValue("supplyChainManagement") * fee);
        resultJson.put("inquiryPriceUnit", quiryJson.get("XSDJ"));
        resultJson.put("inquiryPriceLimit", quiryJson.get("XSXJ"));
        resultJson.put("inquiryPurchaseUnit", quiryJson.get("CGDJ"));
        resultJson.put("oldInquiryNumber", quiryJson.getString("XJDH"));
        resultJson.put("haveOffice","暂无报价");
        if (resultJson.getString("uniqueValue")!=null)resultJson.put("haveOffice","已有报价");
        //前端要求需要返回的
        if(quiryJson.getString("HYZT") != null && "0".equals(quiryJson.getString("HYZT").trim())){
            resultJson.put("serviceState", false);
        }else {resultJson.put("serviceState", true);}
        resultJson.put("innerBusinessKey", quiryJson.getString("SPID"));
        resultJson.put("inquirySelectFlag", 1);
        //单独返回默认销售数量
        resultJson.put("saleQty", 1);
        //询价单号
        Double yjdhsc = quiryJson.getDouble("YJDHSC");
        if (yjdhsc!=null){
            Double yjdhts = yjdhsc/24;
            resultJson.put("expectedArrivalTimeTemp", yjdhts);
            resultJson.put("expectedArrivalTime", yjdhsc);
        }
        resultJson.put("oldInquiryNumber", quiryJson.getString("XJDH"));
        resultJson.put("tagMapAddress", quiryJson.getString("tagMapAddress"));
        resultJson.put("partCode", quiryJson.getString("partCode"));
        resultJson.put("partName", quiryJson.getString("partName"));
        resultJson.put("originalInquiryProduct", quiryJson.getJSONObject("originalInquiryProduct"));
        resultJson.put("inquiryGooodsState", quiryJson.getInteger("HYZT"));
        resultJson.put("supplierRemarks", quiryJson.getString("supplierRemarks"));
        resultJson.put("purchaseRemarks", quiryJson.getString("purchaseInformation"));
        boolean productRule = ((List) this.invoke("cm.consignmentRule.findAllByCategoryAndProvinceAndCity",
                MapUtil.mapper("deptId", belongDept.getId(),
                        "categoryId", quiryJson.getString("PJMCID"), "brandId", quiryJson.getString("PPID"))
        )).size() != 0;
        resultJson.put("productRule", productRule);
        Location location;
        try {
            location = SpringManager.getBean(LocationService.class).findLocationByDept(belongDept, productRule);
            if (productRule) {
                if (location == null) throw new RuntimeException("门店没有设置带安虚拟库，门店名称：" + belongDept.getName());
            } else {
                if (location == null) throw new RuntimeException("未找到门店对应的仓库" + belongDept.getName());
            }
            resultJson.put("location", location);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        Map qryQualityInfo = this.invoke("fn.fnCommunalService.qryQualityInfo", MapUtil.mapper("SPID", quiryJson.getString("SPID"), "PLID", quiryJson.getString("PLID"), "PPID", quiryJson.getString("PPID")));
        if (qryQualityInfo != null) {
            resultJson.put("qualityWarranty", qryQualityInfo.get("qualityWarranty"));
            resultJson.put("qualityMileage", qryQualityInfo.get("qualityMileage"));
        }

        resultJson.put("logisticsMode", quiryJson.get("logisticsMode"));
        if (!StringUtils.isEmpty(quiryJson.get("logisticsMode"))) {
            resultJson.put("carrierId", quiryJson.getJSONObject("logisticsMode").getString("id"));
            resultJson.put("carrierName", quiryJson.getJSONObject("logisticsMode").getString("name"));
        }
        if (resultJson.containsKey("saleQty") && resultJson.containsKey("pftPriceUnit")){
            resultJson.put("salesAmount", Arith.mul(resultJson.getDoubleValue("saleQty"),resultJson.getDoubleValue("pftPriceUnit")));
        }
        return resultJson;
    }


    /**
     * 查找可转询价明细
     * @param request
     * @return
     */
    public JSONObject checkToInquiryItems(SimpleRequest request){
        JSONObject jo = request.getJO();
        String id = jo.getString("id");
        ServicePlan servicePlan = servicePlanRepository.findOne(id);
        JSONObject result = new JSONObject();
        //需要排除不服务的商品去查询是否询价
        JSONObject planJson = new JSONObject(MapUtil.mapped(servicePlan, "servicePlanItems"));
        List inquiryPool = getInquiryPool(planJson);
        List list = servicePlan.getServicePlanItems().stream().filter(servicePlanItem -> {
            return "10".equals(servicePlanItem.getProduct().getProductGroup().getId())||servicePlanItem.isProductRule();
        }).filter(ServicePlanItem::isServiceState).sorted(Comparator.comparing(ServicePlanItem::getPartCode,Comparator.nullsLast(String::compareTo))
        ).map(servicePlanItem ->  chooseToInquiryDialogValue(servicePlanItem,servicePlan.getBelongDept(), inquiryPool,servicePlan)
        ).collect(Collectors.toList());
        result.put("node",list);
        //车头，车尾，名牌照片
        request.setData(MapUtil.mapper("carLicense", servicePlan.getFnCustomerExpand().getCarLicense(), "vendorCode", servicePlan.getFnCustomerExpand().getVendorCode()));
        String pictures = getBean(FnAppCustomerService.class).getPictures(request);
        result.put("pictures", pictures);

        return result;
    }


    /**
     * chooseToInquiry表单需要的参数
     * @param servicePlanItem
     * @param servicePlan
     * @return
     */
    public JSONObject chooseToInquiryDialogValue(ServicePlanItem servicePlanItem,Dept dept, List items,ServicePlan servicePlan){
        JSONObject jsonObject = new JSONObject();
        String oem = servicePlanItem.getPartCode();

        jsonObject.put("partCode", oem);
        jsonObject.put("smartEpcPartName", servicePlanItem.getPartName());
        jsonObject.put("category",servicePlanItem.getProduct().getCategory());
        jsonObject.put("id",servicePlanItem.getId());
        jsonObject.put("servicePlanId",servicePlanItem.getServicePlan().getId());
        jsonObject.put("product",servicePlanItem.getProduct());
        jsonObject.put("saleQty",servicePlanItem.getSaleQty());
        jsonObject.put("primaryPriceUnitShow",servicePlanItem.getPriceUnit());
        jsonObject.put("referTax",servicePlanItem.getReferTax());
        jsonObject.put("priceCostUnitInTax",servicePlanItem.getPriceCostUnitInTax());
        jsonObject.put("supplyChainManagement",servicePlanItem.getSupplyChainManagement());
        jsonObject.put("epcPicture",servicePlanItem.getMapAddress());
        jsonObject.put("productId",servicePlanItem.getProduct().getId());
        jsonObject.put("vin",servicePlan.getFnCustomerExpand().getVin());
        jsonObject.put("price", servicePlanItem.getFourSPrice());
        jsonObject.put("productName",servicePlanItem.getProduct().getName());
        if ("000609,013951".contains(servicePlanItem.getProduct().getCategory().getId())){
            jsonObject.put("note",servicePlanItem.getProduct().getName());
        }
        if ("000609".equals(servicePlanItem.getProduct().getCategory().getId())){
            JSONObject tyreProductJSON = invoke("dc.tyreProduct.findOneERPProductId", MapUtil.mapper("productId", servicePlanItem.getProduct().getId()));
            jsonObject.put("oem", Objects.isNull(tyreProductJSON) ? servicePlanItem.getProduct().getModel() : tyreProductJSON.getString("specification"));
        }
        jsonObject.put("productRule", servicePlanItem.isProductRule());
        checkNowOffice(jsonObject,servicePlanItem.getProduct(),dept,items,servicePlanItem.getPriceUnit(),servicePlanItem.isProductRule());
        return jsonObject;
    }

    /**
     * 过滤转询价商品
     * @param request
     * @return
     */
    public ServicePlan productToInquiry(SimpleRequest request){
        JSONArray servicePlanItems = request.getJO().getJSONArray("servicePlanItems");
        String itemid = servicePlanItems.getJSONObject(0).getString("id");
        ServicePlanItem planItem = servicePlanItemRepository.findOne(itemid);
        ServicePlan servicePlan = planItem.getServicePlan();
        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            servicePlanItem.setNeedInquiry(false);
            servicePlanItems.forEach(item ->{
                JSONObject itemJson = (JSONObject) item;
                if (itemJson.getString("id").equals(servicePlanItem.getId())){
                    if (itemJson.getBoolean("checkData")){
                        servicePlanItem.setNeedInquiry(true);
                        servicePlanItem.setNote(itemJson.getString("note"));
                        servicePlanItem.setOldPicture(itemJson.getString("oldPicture"));
                        servicePlanItem.setSaleQty(itemJson.getDoubleValue("saleQty"));
                    }
                }
            });
        });

        return  this.invoke("fn.service.toInquiry",MapUtil.mapped(servicePlan));

    }

    /**
     * 插入报价信息
     * @param request
     * @return
     */
    public ServicePlan insertOffice(SimpleRequest request){
        ServicePlan servicePlan = request.getO(ServicePlan.class);
        if(servicePlan.getServicePlanItems().size() == 0) return null;

        return getCurrentTimeData(servicePlan);
    }





//    public JSONObject checkNowOffice(JSONObject resultJson,Product product,ServicePlan servicePlan,Double priceUnit){
//        JSONObject jsonService = new JSONObject(MapUtil.mapped(servicePlan,"servicePlanItems"));
//        return checkNowOffice(resultJson,product,servicePlan.getBelongDept(),jsonService,priceUnit);
//    }
//    /**
//     * 查询是否有报价(单个)
//     * @param resultJson    返回结果集
//     * @param product       商品
//     * @param belongDept    所属部门
//     * @param conditionModel 方案主表信息(明细太多尽量去除)
//     * @param priceUnit     销售单价
//     * @return
//     */
//    public JSONObject checkNowOffice(JSONObject resultJson, Product product, Dept belongDept, JSONObject conditionModel, double priceUnit) {
//        resultJson.put("haveOffice", "暂无报价");
//        JSONArray uniqueValueProducts = new JSONArray();
//
//        if (conditionModel.getString("id") != null) {
//            List items = getInquiryPool(conditionModel);
//            if (!items.isEmpty()) {
//                items.forEach(item -> {
//                    JSONObject itemJson = new JSONObject((Map) item);
//                    if (!itemJson.getJSONArray("item").isEmpty()) {
//                        uniqueValueProducts.addAll(itemJson.getJSONArray("item"));
//                    }
//                    if (itemJson.getString("YSPID").equals(product.getId())) {
//                        if (itemJson.getJSONArray("item").isEmpty()) {
//                            resultJson.put("haveOffice", "暂无报价");
//                        } else {
//                            resultJson.put("YSPID", itemJson.getString("YSPID"));
//                            resultJson.put("haveOffice", "已有报价");
//                        }
//                    }
//                });
//            }
//        }
//
//        // 如果存在报价的商品，直接返回
//        if (resultJson.getString("haveOffice").equals("已有报价")) return resultJson;
//
//        /*if ("20".equals(product.getProductGroup().getId())) {
//            resultJson.put("haveOffice", "已有报价");
//        } else*/ if (resultJson.getString("uniqueValue") != null) {
//            resultJson.put("haveOffice", "已有报价");
//        } else if (priceUnit != 0 && "10".equals(product.getProductGroup().getId())) {
//            JSONObject json1 = new JSONObject();
//            List productList = new ArrayList();
//            JSONObject productId = new JSONObject();
//            productId.put("productId", product.getId());
//            productList.add(productId);
//            json1.put("NEW_DEPT_ID", belongDept.getId());
//            json1.put("OLD_DEPT_ID", belongDept.getOrigin());
//            json1.put("productList", productList);
//            JSONArray array = servicePlanDao.queryProductStoreForList(json1);
//
//            JSONArray resultList = array.stream().filter(tempJson -> {
//                JSONObject item = (JSONObject) tempJson;
//                return item.getDoubleValue("GENERAL_STOCK") + item.getDoubleValue("SUB_STOCK") + item.getDoubleValue("STOCK_AMOUNT") <= 0;
//            }).collect(Collectors.toCollection(JSONArray::new));
//
//            if (resultList.size() == 0) resultJson.put("haveOffice", "已有报价");
//        }
//
//        return resultJson;
//    }
//


    /**
     * 判断是否有询价商品
     * @param request
     * @return
     */
    public Boolean checkInquiryGoods(SimpleRequest request){
        JSONObject jo = request.getJO();
        JSONObject conditionModel = jo.getJSONObject("conditionModel");
        List inquiryPool = getInquiryPool(conditionModel);
        return inquiryPool.size()>0;
    }

    /**
     * 查询DC配送范围的商品库存
     * @param request
     * @return
     */
    public Map getProductStock(SimpleRequest request){
        JSONObject jo = request.getJO();
        JSONObject localStore = new JSONObject();
        JSONArray resultLocalStore = new JSONArray();
        int resultLocalStoreNum = 0;
        JSONArray resultAreaStore = new JSONArray();
        int resultAreaStoreNum = 0;
        JSONArray resultHeadStore = new JSONArray();
        int resultHeadStoreNum = 0;

/*      老框架库存帐接口
        JSONObject returnData = piManager.synErp("ipmServicePlanService.getProductStockInfo", MapUtil.mapper("locationId", jo.getString("locationId"),
                "productId",jo.getString("productId")
                ));
*/

        Location locationId = locationRepository.findOne(jo.getString("locationId"));
        Double localStoreUsableQty = servicePlanDao.queryLocalStore(jo);//本地库存
        JSONArray productForDC = servicePlanDao.queryProductForDC(jo);//父仓库

        localStore.put("companyId",locationId.getCompany().getId());
        localStore.put("companyName",locationId.getCompany().getName());
        localStore.put("usableQty",localStoreUsableQty);
        resultLocalStoreNum+=localStoreUsableQty;
        resultLocalStore.add(localStore);
        for (Object location : productForDC) {

            JSONObject jsonObject = (JSONObject)location;
            JSONObject result = new JSONObject();

            List<Stock> stockList = stockRepository.findByLocationAndProduct(jsonObject.getString("ID"),jo.getString("productId"));

            result.put("companyId",jsonObject.getString("COMPANY_ID"));
            result.put("companyName",jsonObject.getString("COMPANY_NAME"));
            result.put("usableQty",stockList.size()>0?stockList.get(0).getUsableQty():0);

            if ("000122".equals(jsonObject.getString("DEPOT_LEVEL_ID"))){//门店
                resultLocalStore.add(result);
                resultLocalStoreNum+=stockList.size()>0?stockList.get(0).getUsableQty():0;
            }else if ("000123".equals(jsonObject.getString("DEPOT_LEVEL_ID"))){//区域中心仓
                resultAreaStore.add(result);
                resultAreaStoreNum+=stockList.size()>0?stockList.get(0).getUsableQty():0;
            }else if ("000121".equals(jsonObject.getString("DEPOT_LEVEL_ID"))){//总仓
                resultHeadStore.add(result);
                resultHeadStoreNum+=stockList.size()>0?stockList.get(0).getUsableQty():0;
            }

        }
        Map result = MapUtil.mapper("localStoreLocal", resultLocalStore,
                "localStoreNum", resultLocalStoreNum,
                "areaStoreLocal", resultAreaStore,
                "areaStoreNum", resultAreaStoreNum,
                "headStoreLocal", resultHeadStore,
                "headStoreNum", resultHeadStoreNum,
                "referTax", jo.getInteger("referTax") == null ? 0 : jo.getInteger("referTax"),
                "supplyChainManagement", jo.getInteger("supplyChainManagement") == null ? 0 : jo.getInteger("supplyChainManagement"),
                "productId", jo.getString("productId"),
                "productName", jo.getString("productName")
        );
        return result;
    }

    public Page getProductsStockInfo(SimpleRequest request){
        JSONObject jo = request.getJO();
        JSONObject plan = jo.getJSONObject("data");
        String id = plan.getString("id");
        List list = new ArrayList();
        JSONArray planItems;
        JSONObject dept;
        if (id.startsWith("FW")){
            planItems = plan.getJSONArray("servicePlanItems");
            dept = plan.getJSONObject("belongDept");
        }else {
            planItems = plan.getJSONArray("lossQuotationItems");
            dept = plan.getJSONObject("fixedLossDept");
        }
        planItems.forEach(servicePlanItem->{
            JSONObject jsonObject = (JSONObject) servicePlanItem;
            JSONObject product = jsonObject.getJSONObject("product");
            list.add(this.invoke("fn.service.getProductStock",MapUtil.mapper("productId",product.getString("id"),
                    "productName",product.getString("name"),
                    "referTax",jsonObject.getInteger("referTax"),
                    "supplyChainManagement",jsonObject.getInteger("supplyChainManagement"),
                    "deptId",dept.getString("id"),
                    "locationId",jsonObject.getJSONObject("location").getString("id")
            )));
        });
        return pageInfo(jo,list,true);
    }

    public Object findStockByProduct(SimpleRequest request) {
        JSONObject param = request.getJO();
        // 外采
        if (request.getJO().getJSONObject("conditionModel").get("externalInquiryItems") != null) {
            String id = request.getJO().getJSONObject("conditionModel").getString("sourceBusinessKey");
            JSONObject dept = new JSONObject();
            if (param.getJSONObject("conditionModel").getString("sourceBusinessType").equals("ServicePlan")) {
                dept.put("id", SpringManager.getBean(ServicePlanRepository.class).findOne(id).getBelongDept().getId());
                param.getJSONObject("conditionModel").put("belongDept",dept);
            } else {
                dept.put("id", lossQuotationRepository.findOne(id).getFixedLossDept().getId());
                param.getJSONObject("conditionModel").put("fixedLossDept",dept);
            }
        }
        return ServicePlanFactory.getServicePlanMethod().findStockByProduct(param, switched);
    }
    /**
     * 手动分页
     * @param jo
     * @param cross
     * @return
     */
    public PageImpl pageInfo(JSONObject jo, List cross,Boolean fixPage){
        int fixNum = 0;
        if (fixPage)fixNum+=1;
        int size = ((Integer) jo.get("page")-fixNum)*(Integer) jo.get("size");
        List result = new ArrayList<>();
        for (int i = size+1; i <= size+(Integer) jo.get("size"); i++) {
            if (cross.size()>=i)result.add(cross.get(i-1));
        }
        Pageable pageable = PageRequest.of(((Integer) jo.get("page")), (Integer) jo.get("size"));
        PageImpl page = new PageImpl(result, pageable, cross.size());
        return page;
    }


    /**
     * 质检生成旧件入库单
     * @param request
     */
    public void createUsedStore(SimpleRequest request) {
        ServicePlan o = request.getO(ServicePlan.class);
        ServicePlan servicePlan = servicePlanRepository.findOne(o.getId());
        if (servicePlan == null) return;
        if (!"qualityTest".equals(servicePlan.getState())) return;

        Location location = locationRepository.findAll(JpaDsl.toCriteria("depot.dept.id", "EQ", servicePlan.getBelongDept().getId(),
                "usage.id", "EQ", "1")).get(0);

        if (!checkCompanyIsUseUsed(location.getCompany())) return;

        UsedStore usedStore = new UsedStore();
        usedStore.setDept(servicePlan.getServiceDept());
        usedStore.setLocation(location);
        usedStore.setCompany(servicePlan.getCompany());
        usedStore.setSource(servicePlan.getId());
        usedStore.setSourceBusinessType(servicePlan.getBusinessType());
        usedStore.setSourceBusinessTypeName("服务方案");
        if ("LossQuotation".equals(servicePlan.getSourceBusinessType())) usedStore.setInsuranceRecoverySign(true);
        usedStore.setStoreType(businessAttributeValueRepository.findOne("UsedStore.storeType.normal"));
        usedStore.setRemark("服务方案质检产生旧件入库单");
        if (servicePlan.getQualityTestUid() != null) usedStore.setCreator(servicePlan.getQualityTestUid().getId());
        PartyRole system = SpringManager.getBean(PartyRoleRepository.class).findOne("system");
        usedStore.setCreator(system.getId());
        List<User> userInfo = SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id", "system"));
        usedStore.setUserId(userInfo.get(0).getId().toString());
        List<UsedStoreItem> usedStoreItems = new ArrayList();
        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            List<Used> useds = usedRepository.findAll(JpaDsl.toCriteriaByEq("usedClassifyItems.classify",servicePlanItem.getProduct().getClassify()));
            if (useds.size()>0 && "10".equals(servicePlanItem.getProduct().getProductGroup().getId())
                               && (servicePlanItem.getSaleQty() - servicePlanItem.getQtyEnd() > 0)
                               && checkInquirySelectFlag(servicePlanItem)){
                UsedStoreItem usedStoreItem = new UsedStoreItem();
                usedStoreItem.setOriginLine(servicePlanItem.getId());
                usedStoreItem.setProduct(servicePlanItem.getProduct());
                usedStoreItem.setSourceUom(servicePlanItem.getUom());
                usedStoreItem.setQytSource(servicePlanItem.getSaleQty() - servicePlanItem.getQtyEnd());//来源数量
                usedStoreItem.setQtyStore(servicePlanItem.getSaleQty() - servicePlanItem.getQtyEnd());//旧件入库数量
                usedStoreItems.add(usedStoreItem);
            }
        });
        if (usedStoreItems.size()==0) return;
        usedStore.setUsedStoreItems(usedStoreItems);
        invoke("used.usedStore.create",MapUtil.mapped(usedStore));
    }

    private boolean checkCompanyIsUseUsed(PartyRole company) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("SYS_RQ",new Date());
        jsonObject.put("conditionStrategyId","PD_JJGL");
        AccessProvider accessProvider = SpringManager.getBean(AccessProviderRepository.class).findByCompany(company.getId());
        if (accessProvider == null) return false;
        jsonObject.put("ACCESS_PROVIDER_ID",accessProvider.getId());
        try {
            Object obj = this.invoke("condition.execConditionStrategy", jsonObject);
        }catch (Exception e){
            return false;
        }
        return true;
    }


    public Map getCarInfo(SimpleRequest request) {
        JSONObject jo = request.getJO();
        Dept dept = deptRepository.findOne(jo.getJSONObject("dept").getString("id"));

        return carInformation(jo.getJSONObject("customerCar"),dept);
    }

    /**
     * 获取接车信息
     * -没有则返回空字符串
     * -有则返回字符串 "接车人名称 - 接车时间"
     * @param customerCar
     * @param dept
     * @return
     */
    private Map carInformation(JSONObject customerCar,Dept dept){
        //查询有无审核状态的接车单
        PickUpCar pickCar = SpringManager.getBean(PickUpCarRepository.class).findByLicenseNumberAndDeptAndState(customerCar.getString("carLicense"), dept, "approve").stream().findFirst().orElseGet(()->null);
        //如果有审核的接车单
        if (pickCar!=null){
            //没有接车人就只返回时间
            if (pickCar.getCreator()==null)return appendCarInfoMap(null,pickCar.getCreateDate(), pickCar.getId(), pickCar.getInnerBusinessType());
            //返回名字+接车时间
            PartyRole partyRole = SpringManager.getBean(PartyRoleRepository.class).findOne(pickCar.getCreator());
            return appendCarInfoMap(partyRole.getName(),pickCar.getCreateDate(), pickCar.getId(), pickCar.getInnerBusinessType());
        }

        //如果没有审核的接车单 则查询有无内协交接车
        if (pickCar==null){
            //通过车牌，寻找有效门店内协接车单，有效的只能有一张 都没有就直接返回没有
            InnerPickDeliveryUpCar innerPickDeliveryUpCar = null;
            try {
                innerPickDeliveryUpCar = SpringManager.getBean(InnerPickDeliveryUpCarService.class).getInnerPickDeliveryUpCar(dept,customerCar.getString("carLicense"));
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (innerPickDeliveryUpCar==null)return new HashMap();
            //如果有内协交接车 就判断是否已接车
            InnerPickDeliveryUpCarItem pickDeliveryUpCarItem = innerPickDeliveryUpCar.getInnerPickDeliveryUpCarItemList().stream()
                    .filter(innerPickDeliveryUpCarItem -> innerPickDeliveryUpCarItem.getNodeDescription().equals("get"))
                    .findFirst().orElseGet(() -> null);
            if (pickDeliveryUpCarItem==null)return new HashMap();
            //没有接车人就只返回时间
            PartyRole operate = pickDeliveryUpCarItem.getOperateUid();
            if (operate==null)return appendCarInfoMap(null,pickDeliveryUpCarItem.getOperateDate(), innerPickDeliveryUpCar.getId(), innerPickDeliveryUpCar.getInnerBusinessType());
            //返回名字+接车时间
            return appendCarInfoMap(operate.getName(),pickDeliveryUpCarItem.getOperateDate(), innerPickDeliveryUpCar.getId(), innerPickDeliveryUpCar.getInnerBusinessType());
        }
        return new HashMap();
    }

    private Map appendCarInfoMap(String creator,Date createDate, String id, String innerBusinessType) {
        if (creator==null){
            return mapper(
                    "carInfo", DateUtil.format(createDate, DateUtil.SHOW_DATETIME_FORMAT),
                    "creator", "--",
                    "createDate", createDate,
                    "id", id,
                    "pickCarType", innerBusinessType
            );
        }else {
            return mapper(
                    "carInfo", creator + " - " + DateUtil.format(createDate, DateUtil.SHOW_DATETIME_FORMAT),
                    "creator", creator,
                    "createDate", createDate,
                    "id", id,
                    "pickCarType", innerBusinessType
            );
        }
    }

    public ServicePlan createPlanTest(SimpleRequest request) {
        ServicePlan newPlan = new ServicePlanBuilder(request)
                .setCarLicense("粤RRGHH6")
                .setState("confirm")
                .setItems(MapUtil.mapper("0000001579",
                        mapper("product", mapper("id", "0000001579"),
                                "saleQty", "1")
                        , "0000002001", mapper("product", mapper("id", "0000002001"),
                                "saleQty", "1")))
                .fastBuildServicePlan();
        return newPlan;
    }

    public List<Map> findWorkHourClassify(SimpleRequest request){
        List<Map> result = new ArrayList();
        result.add(MapUtil.mapper("id","S0101","name","洗车类工时"));
        result.add(MapUtil.mapper("id","S0102","name","美容类工时"));
        result.add(MapUtil.mapper("id","S0103","name","保养类工时"));
        result.add(MapUtil.mapper("id","S0104","name","维修类工时"));
        result.add(MapUtil.mapper("id","S0105","name","钣金类工时"));
        result.add(MapUtil.mapper("id","S0106","name","油漆类工时"));
        result.add(MapUtil.mapper("id","S0107","name","外加工工时"));
        result.add(MapUtil.mapper("id","S0108","name","救援类工时"));
        return result;
    }

    /**
     * 方案订单详情明细
     * @param request
     * @return
     */
    public JSONObject queryPlanDetails(SimpleRequest request){
        JSONObject result = new JSONObject();
        JSONObject jo = request.getJO();
        String id = jo.getString("id");
        ServicePlan servicePlan = servicePlanRepository.findOne(id);
        JSONObject param = new JSONObject(MapUtil.mapper("ID", id));
        //主表信息
        result.putAll(servicePlanDao.queryPlanDetails(param));
        //明细详情
        result.put("itemDetails", servicePlanDao.queryPlanItemAmount(param));
        //获取总预估提成
        result.put("estimatedCommission",servicePlan.totalEstimatedCommission());
        //支付信息
        result.put("payDetails", servicePlanDao.queryPayDetails(param));
        //获取主辅销
        planItemGetSalerName(result, servicePlan);
        //提成
        getProcessTC(result, param);
        //零售单折扣信息
        Double discount = this.invoke("retail.order.findDiscountByOriginOrSource",mapper("origin",id,"source",id));

        String amount = String.format(
                "商品总额:                ￥%s\n折扣总额:                -￥%s\n应付总额:                ￥%s\n",
                servicePlan.getSalesAmountShow(),discount , servicePlan.getSalesAmountShow()-discount
        );
        result.put("amount", amount);
        result.put("msg",
                "1.应收 = 销售金额 - 折扣总额 \n" +
                "2.折扣总额 = 卡券折扣金额 + 红包抵扣 + 保呗抵扣 + 异业抵扣"
        );

        return result;
    }

    /**
     * 各工序施工提成
     * @param result
     * -result.main_sale_tc 主销总提成
     * -result.sup_sale_tc 辅销总提成
     * -result.worker* 工序* 提成
     * @param param 入参
     * -param.id 方案编码
     */
    private void getProcessTC(JSONObject result, JSONObject param) {
        JSONArray salerTC = servicePlanDao.querySalerTC(param);
        result.put("main_sale_tc", salerTC.stream().mapToDouble(o ->((JSONObject)o).getDoubleValue("MAIN_SALESMAN_TCJE")).sum());
        result.put("sup_sale_tc", salerTC.stream().mapToDouble(o ->((JSONObject)o).getDoubleValue("SUB_SALESMAN_TCJE")).sum());
        JSONArray workTC = servicePlanDao.queryWorkTC(param);
        workTC.forEach(o -> {
            JSONObject jsonObject = (JSONObject) o;
            result.put("worker"+jsonObject.getString("PROCESS"), jsonObject.getString("WORKER"));
            result.put("worker"+jsonObject.getString("PROCESS")+"_amount", jsonObject.getDoubleValue("TC_AMT"));
        });
    }

    /**
     * 方案下所有明细主辅销名字
     * @param result
     * -result.mainSale
     * -result.supSaler
     * -字符串格式:"name1;name2;"
     * @param servicePlan
     */
    private void planItemGetSalerName(JSONObject result, ServicePlan servicePlan) {
        StringBuffer mainSale = new StringBuffer();
        StringBuffer supSaler = new StringBuffer();
        servicePlan.getServicePlanItems().stream().map(ServicePlanItem::getMainSaler).distinct().forEach(partyRole -> { if (partyRole != null)  mainSale.append(partyRole.getName() + ";"); });
        servicePlan.getServicePlanItems().stream().map(ServicePlanItem::getSupSaler).distinct().forEach(partyRole -> { if (partyRole != null)  supSaler.append(partyRole.getName() + ";"); });
        result.put("mainSale", mainSale.toString().isEmpty()?"--":mainSale.toString());
        result.put("supSaler", supSaler.toString().isEmpty()?"--":supSaler.toString());
    }


    public com.apestech.framework.json.JSONObject fnServicePlanItemQuery(SimpleRequest request) throws Exception {
        JSONObject jo = request.getJO();
        JSONArray condition = jo.getJSONArray("condition");
        JSONArray newCondition = new JSONArray();
        if (condition != null) {
            for (int i = 0; i < condition.size(); i++) {
                if(changeConditionByAdoptionState(condition,i,newCondition)) continue;
//                if(changeConditionByState(condition,i,newCondition)) continue;
                if(changeConditionById(condition,i,newCondition)) continue;
                if(changeMaintenanceOrderByState(condition,i,newCondition,"WORK_STATE")) continue;
                if(changeMaintenanceOrderByState(condition,i,newCondition,"TICKETS_STATE")) continue;
                newCondition.add(condition.get(i));
            }
            jo.put("condition", newCondition);
        }
        return com.apestech.framework.json.JSON.toJSON(jo.toJSONString());
    }

    public com.apestech.framework.json.JSONObject fnServicePlanQuery(SimpleRequest request) throws Exception {
        JSONObject jo = request.getJO();
        JSONArray condition = jo.getJSONArray("condition");
        JSONArray newCondition = new JSONArray();
        if (condition != null) {
            for (int i = 0; i < condition.size(); i++) {
//                if(changeConditionByState(condition,i,newCondition)) continue;
                if(changeConditionById(condition,i,newCondition)) continue;
                newCondition.add(condition.get(i));
            }
            jo.put("condition", newCondition);
        }
        return com.apestech.framework.json.JSON.toJSON(jo.toJSONString());
    }

    private boolean changeMaintenanceOrderByState(JSONArray condition,int i,JSONArray newCondition,String state){
        if (!state.equals(condition.getJSONObject(i).getString("field"))) return false;
        JSONArray value = condition.getJSONObject(i).getJSONArray("value");
        JSONArray newValue = new JSONArray();
        condition.getJSONObject(i).getJSONArray("value").forEach(item ->{
            if(!"null".equals(item)) {
                newValue.add(item);
            }else{
                JSONObject workStateFitting = new JSONObject();
                workStateFitting.put("field",state + "_FITTING");
                workStateFitting.put("operator","EQ");
                workStateFitting.put("value", true);
                newCondition.add(workStateFitting);
            }
        });
        if (newValue.size() != 0){
            JSONObject stateSQL = new JSONObject();
            stateSQL.put("field",state);
            stateSQL.put("operator","IN");
            stateSQL.put("value", newValue);
            newCondition.add(stateSQL);
        }
        return true;
    }

    private boolean changeConditionByAdoptionState(JSONArray condition,int i,JSONArray newCondition){
        if ("ADOPTION_STATE".equals(condition.getJSONObject(i).getString("field"))){
            JSONArray value = condition.getJSONObject(i).getJSONArray("value");
            condition.getJSONObject(i).getJSONArray("value").forEach(item ->{
                String field = (String) item;
                JSONObject json = new JSONObject();
                switch (field){
                    case "already": json.put("field","ADOPTION_STATE_ALREADY");break;
                    case "not": json.put("field","ADOPTION_STATE_NOT");break;
                    case "part": json.put("field","ADOPTION_STATE_PART");break;
                }
                json.put("operator","EQ");
                json.put("value","true");
                newCondition.add(json);
            });
            return true;
        }
        return false;
    }

    private boolean changeConditionByState(JSONArray condition,int i,JSONArray newCondition){
        // 将服务方案列表的方案状态(待质检)提取出来
        if ("STATE".equals(condition.getJSONObject(i).getString("field"))){
            JSONArray value = condition.getJSONObject(i).getJSONArray("value");
            JSONArray newValue = new JSONArray();
            condition.getJSONObject(i).getJSONArray("value").forEach(item ->{
                if(!"awaitQuality".equals(item)) {
                    newValue.add(item);
                }else{
                    JSONObject awaitQuality = new JSONObject();
                    awaitQuality.put("field","awaitQuality");
                    awaitQuality.put("operator","EQ");
                    awaitQuality.put("value", true);
                    newCondition.add(awaitQuality);
                }
            });
            if (newValue.size() != 0){
                JSONObject stateSQL = new JSONObject();
                stateSQL.put("field","STATE_");
                stateSQL.put("operator","IN");
                stateSQL.put("value", newValue);
                newCondition.add(stateSQL);
            }
            return true;
        }
        return false;
    }

    private boolean changeConditionById(JSONArray condition,int i,JSONArray newCondition){
        // 将订单分类：方案、来源、第三方
        if ("ID_SOURCE_FROM".equals(condition.getJSONObject(i).getString("field"))){
            String field = condition.getJSONObject(i).getString("field");
            String operator = condition.getJSONObject(i).getString("operator");
            String value = condition.getJSONObject(i).getString("value");
            if (!Objects.isNull(value)){
                if (value.startsWith("FW")){
                    field = "ID";
                } else if (value.startsWith("DS")){
                    field = "SOURCE_FROM";
                }
            }
            JSONObject stateSQL = new JSONObject();
            stateSQL.put("field",field);
            stateSQL.put("operator",operator);
            stateSQL.put("value", value);
            newCondition.add(stateSQL);
            return true;
        }
        //PICK_CAR_DATE_TEMP 处理接车日期
        if ("PICK_CAR_DATE_TEMP".equals(condition.getJSONObject(i).getString("field"))){
            JSONObject json = new JSONObject();
            if("GTE".equals(condition.getJSONObject(i).getString("operator"))){
                json.put("field","PICK_CAR_DATE_TEMP_START");
                json.put("operator","EQ");
                json.put("value",condition.getJSONObject(i).getString("value"));
                json.put("type","date");
                newCondition.add(json);
            }else if("LTE".equals(condition.getJSONObject(i).getString("operator"))){
                json.put("field","PICK_CAR_DATE_TEMP_END");
                json.put("operator","EQ");
                json.put("value",condition.getJSONObject(i).getString("value"));
                json.put("type","date");
                newCondition.add(json);
            }
            return true;
        }
        return false;
    }

    public boolean checkInquirySelectFlag(ServicePlanItem servicePlanItem){
        return servicePlanItem.getInquirySelectFlag() == null || servicePlanItem.getInquirySelectFlag().equals(1);
    }

    public Object checkShowPriceUnitTips(SimpleRequest re){
        JSONObject reJO = re.getJO();
        JSONArray item = reJO.getJSONArray("item");
        String carNumber = reJO.getString("carNumber");
        List<String> ids =new ArrayList<>();
        Map<String, JSONObject> productMap = new HashMap<>();
        List<JSONObject> result = item.stream().map(i -> {
            JSONObject jo = (JSONObject)i;
            String productId = jo.getJSONObject("product").getString("id");
            jo.put("showPriceUnitTips",false);
            if (StringUtils.hasText(jo.getString("carrierId"))) jo.put("logisticsMode", MapUtil.mapper("id", jo.getString("carrierId"), "name", jo.getString("carrierName")));
            productMap.put(productId,jo);
            ids.add(productId);
            return jo;
        }).collect(Collectors.toList());
        //批量处理
        findShowPriceUnitTips(ids,carNumber,productMap);
        return result;
    }

    public Object checkShowPriceUnitTipsByDetail(SimpleRequest re){
        JSONObject reJO = re.getJO();
        String productId = reJO.getString("productId");
        Double primaryPriceUnitShow = reJO.getDouble("primaryPriceUnitShow");
        String carNumber = reJO.getString("carNumber");
        String id = reJO.containsKey("id") ? reJO.getString("id") : null;
        return findShowPriceUnitTips(productId,primaryPriceUnitShow,carNumber,id);
    }

    public boolean findShowPriceUnitTips(String productId,Double amount,String carNumber,String id){
        String finalId = id;
        if(id==null)id="";
        List<Map> showPriceUnitTips = servicePlanItemRepository.findShowPriceUnitTips(productId, amount, carNumber,id);
        showPriceUnitTips = showPriceUnitTips.stream()
                .filter(showPriceUnitTip -> (finalId == null || !showPriceUnitTip.get("ID").equals(finalId)) && ((BigDecimal)showPriceUnitTip.get("primary_price_unit_show")).doubleValue() != 0)
                .collect(Collectors.toList());
        return showPriceUnitTips.size() > 0;
    }

    public boolean findShowPriceUnitTips(List productIds,String carNumber,Map<String,JSONObject> productMap){
        List<Map> showPriceUnitTips = servicePlanItemRepository.findShowPriceUnitTips(productIds, carNumber);
        showPriceUnitTips = showPriceUnitTips.stream()
                .filter(
                        showPriceUnitTip -> {
                            double primaryPriceUnitShow = ((BigDecimal) showPriceUnitTip.get("primary_price_unit_show")).doubleValue();
                            JSONObject jsonObject = productMap.get(showPriceUnitTip.get("PRODUCT_ID"));
                            String id = jsonObject.getString("id")==null?"":jsonObject.getString("id");
                            return  ( !showPriceUnitTip.get("ID").equals(id)) &&
                                    primaryPriceUnitShow != 0 &&
                                    jsonObject.getDoubleValue("primaryPriceUnitShow") != primaryPriceUnitShow;
                        }
                )
                .collect(Collectors.toList());
        for (Map showPriceUnitTip : showPriceUnitTips) {
            JSONObject jsonObject = productMap.get(showPriceUnitTip.get("PRODUCT_ID"));
            jsonObject.put("showPriceUnitTips",true);
        }
        return true;
    }

    /**
     * 显示三个月未确定的明细
     * @param re
     * @return
     */
    public Object findPriceUnitNotEquals(SimpleRequest re){
        JSONObject reJo = re.getJO();
        String productId = reJo.getString("productId");
        Double primaryPriceUnitShow = reJo.getDouble("primaryPriceUnitShow");
        String carNumber = reJo.getString("carNumber");
        String itemId = reJo.getString("id");
        List<Map> list = servicePlanItemRepository.findShowPriceUnitTips(productId, primaryPriceUnitShow,carNumber,itemId);
        if (list.size() <= 0) return null;
        // 过滤商品id与价格相同的明细
        List<Map> filterList = new ArrayList();
        filterList.add(list.get(0));
        for (Map map : list) {
            boolean flag = true;
            for (Map filterMap : filterList) {
                if (    (map.get("PRIMARY_PRICE_UNIT_SHOW").equals(filterMap.get("PRIMARY_PRICE_UNIT_SHOW"))
                        && map.get("PRODUCT_ID").equals(filterMap.get("PRODUCT_ID"))) ){
                    flag = false;
                    break;
                }
            }
            if (flag) filterList.add(map);
        }
        List<String> ids = filterList.stream().filter(map -> ((BigDecimal)map.get("PRIMARY_PRICE_UNIT_SHOW")).doubleValue() != 0).map(i -> {
            Map itemMap =  (Map)i;
            return itemMap.get("ID").toString();
        }).collect(Collectors.toList());
        if (ids.size() == 0) return null;
        List<ServicePlanItem> servicePlanItems = servicePlanItemRepository.findAll(JpaDsl.toCriteria("id", "in", ids));
        // 数据封装
        List<Object> result = servicePlanItems.stream().map(i -> {
            JSONObject jo = new JSONObject();
            jo.put("productId", "[" + i.getProduct().getId() + "]" + i.getProduct().getName());
            jo.put("primaryPriceUnitShow",i.getPrimaryPriceUnitShow());
            jo.put("saleQty", i.getSaleQty());
            jo.put("createDate",DateUtil.format(i.getServicePlan().getCreateDate(),DateUtil.SHOW_DATETIME_FORMAT));
            return jo;
        }).collect(Collectors.toList());
        return MapUtil.mapper("quoteRecordsItems",result);
    }

    public JSONArray queryCarrierFrom(SimpleRequest simpleRequest) {
        JSONObject getJO = simpleRequest.getJO();
        JSONArray newBindingCarriers = new JSONArray();
        String externalGysid = getJO.getString("EXTERNAL_GYSID");
        if ("00004465".equals(externalGysid)) {
            newBindingCarriers.add(MapUtil.mapper("id", "--", "name", "--"));
            return newBindingCarriers;
        }

        if (StringUtils.hasText(externalGysid)) {
            Enumeration enumeration = enumerationRepository.findByTypeAndCode("logisticsMode", "merchant");
            newBindingCarriers.add(MapUtil.mapper("id", enumeration.getId(), "name", enumeration.getDescription()));
            return newBindingCarriers;
        }

        // 后期如果无其他变动，以下代码可删除
  /*      if (StringUtils.hasText(externalGysid)) {
            String carrierDataStr = "";
            try {
                carrierDataStr = invoke("fn.servicePlan.queryCarrier", getJO);
            } catch (Exception e) {
                if (e.getMessage().indexOf("发生异常，请检查连接") != -1) throw new RuntimeException("数据加载中，请稍候~");
                throw new RuntimeException(e.getMessage());
            }
            JSONArray body = JSONObject.parseObject(carrierDataStr).getJSONArray("body");
            JSONArray bindingCarriers = body.getJSONObject(0).getJSONArray("bindingCarriers");

            bindingCarriers.forEach(bindingCarrier -> {
                JSONObject newBindingCarrier = new JSONObject();
                newBindingCarrier.put("id", ((JSONObject) bindingCarrier).getString("carrierId"));
                newBindingCarrier.put("name", ((JSONObject) bindingCarrier).getString("carrierName"));
                newBindingCarriers.add(newBindingCarrier);
            });
            return newBindingCarriers;
        }
*/

        List<Enumeration> findByType = enumerationRepository.findByType("logisticsMode");
        findByType.forEach(enumeration -> {
            JSONObject newBindingCarrier = new JSONObject();
            newBindingCarrier.put("id", enumeration.getId());
            newBindingCarrier.put("name", enumeration.getDescription());
            newBindingCarriers.add(newBindingCarrier);
        });

        return newBindingCarriers;
    }

    @Listener(topic = "fn.servicePlanceService.queryInquireResultFrom")
    public void queryInquireResultForm(SimpleRequest simpleRequest) {
        JSONObject jo = simpleRequest.getJO();
        Store store = SpringManager.getBean(StoreRepository.class).findByDept(deptRepository.findOne(jo.getString("belongDeptId")));
        try {
            invoke("fn.servicePlanceService.queryInquireResult", MapUtil.mapper("storeId", store.getCode(), "servicePlanId", jo.getString("servicePlanId")));
        } catch (Exception e) {
            System.out.println("--------------" + e.getMessage());
        }
    }

    public JSONObject findLockInquir(SimpleRequest simpleRequest) {
        JSONObject jo = simpleRequest.getJO();
        JSONObject returnResult = new JSONObject();
        List<Map> findLockInquir = servicePlanItemRepository.findLockInquir(jo.getString("servicePlanId"), jo.getString("oldInquiryNumber"));
        List uniqueValues = findLockInquir.stream().map(lockItem -> {
            Map lockItemM = (Map)lockItem;
            if (!StringUtils.isEmpty(lockItemM.get("UNIQUE_VALUE")))
                return lockItemM.get("UNIQUE_VALUE");
            else
                return null;
        }).filter(locakStr -> !StringUtils.isEmpty(locakStr)).collect(Collectors.toList());
        returnResult.put("item", uniqueValues);
        return returnResult;
    }

    // 分解标记图片返回图片地址
    public List obtainTagImages(String tagImages) {
        List<BusinessParam> findAllByQueryKey = SpringManager.getBean(BusinessParamRepository.class).findAllByQueryKey("systemEnvironment");
        JSONArray tagImagesArray = JSONObject.parseArray(tagImages);
        if (tagImagesArray == null) return new ArrayList();
        List returnImageUrls = new ArrayList();
        tagImagesArray.forEach(singleTagImage -> {
            String fix = "pro".equals(findAllByQueryKey.get(0).getValue())?"https://fnhq.jekunauto.com/erp/":"http://test.fnhq.jekunauto.net/erp/";
            String url = fix + ((JSONObject) singleTagImage).getString("url");
            returnImageUrls.add(url);
        });
        return returnImageUrls;
    }

//    private Object writeBackServicePlan(SimpleRequest request) {
//        Pick pick = request.getO(Pick.class);
//        // 获取要货单
//        ProductRequire productRequire = null;
//        switch (pick.getOriginBusinessType()){
//            case "PurchaseOrder":  // 采购订单
//                productRequire = productRequireByPurchaseOrder(pick);
//                break;
//            case "Transfer":  // 转储订单
//            case "CrossCompanyTransferNew":  // 调拔单
//                productRequire = productRequireExpand(pick);
//            break;
//            default:return null;
//        }
//        if (Objects.isNull(productRequire)) return null;
//        // 获取服务方案单
//        String source = productRequire.getSource();
//        if (Objects.isNull(source) || !source.startsWith("FW")) return null;
//        ServicePlan servicePlan = servicePlanRepository.findOne(source);
//        if (Objects.isNull(servicePlan)) return null;
//        // 将交货明细的完成数量同步到服务方案明细中
//        pick.getPickItems().stream().forEach(pickItem -> {
//            servicePlan.getServicePlanItems().stream().forEach(item ->{
//                if (!Objects.isNull(pickItem.getProduct()) && !Objects.isNull(item.getProduct())
//                        && pickItem.getProduct().getId().equals(item.getProduct().getId())) {
//                    item.setQtyDelivery(pickItem.getQtyDone());
//                }
//            });
//        });
//        return updateOnly(servicePlan);
//    }

    private ProductRequire productRequireByPurchaseOrder(Pick pick){
        PurchaseOrder purchaseOrder = purchaseOrderRepository.findOne(pick.getOrigin());
        if (Objects.isNull(purchaseOrder) || StringUtils.isEmpty(purchaseOrder.getProductRequire())) return null;
        return productRequireRepository.findOne(purchaseOrder.getProductRequire());
    }

    private ProductRequire productRequireExpand(Pick pick){
        ProductRequireExpand productRequireExpand = productRequireExpandRepository.findAll(JpaDsl.toCriteriaByEq("distributionId", pick.getOrigin())).stream().findFirst().orElse(null);
        if (Objects.isNull(productRequireExpand) || StringUtils.isEmpty(productRequireExpand.getOrigin())) return null;
        return productRequireRepository.findOne(productRequireExpand.getOrigin());
    }

    public void workStateTermination(List<MaintenanceOrder> maintenanceOrders,ServicePlan servicePlan){
        if (Objects.isNull(maintenanceOrders) || maintenanceOrders.size() == 0) return;
        servicePlan.getServicePlanItems().stream().forEach(servicePlanItem -> {
            maintenanceOrders.stream().forEach(maintenanceOrder -> {
                if (servicePlanItem.getId().equals(maintenanceOrder.getServicePlanItem().getId())){
                    servicePlanItem.setWorkState("termination");
                    if (!Objects.isNull(servicePlanItem.getParentServicePlanItem())) servicePlanItem.getParentServicePlanItem().setWorkState("termination");
                }
            });
        });
    }

    private void confirmItemState(ServicePlan servicePlan) {
        servicePlan.getServicePlanItems().forEach(item ->{
            item.setState("confirm");
            if (item.isServiceState() && ("20".equals(item.getProduct().getProductGroup().getId()) || item.isProductRule())){
                if (!Objects.isNull(item.getParentServicePlanItem())) item.getParentServicePlanItem().setWorkState("wait");
                item.setWorkState("wait");
            }
        });
    }

    /**
     *  服务方案单确认生成审核的要货单后回写服务方案明细
     * @param servicePlan
     */
    public void itemQtyRequire(ServicePlan servicePlan){
        ProductRequire productRequire = productRequireRepository.findAll(JpaDsl.toCriteria("source","EQ",servicePlan.getId(),
                                                                                                   "state","IN",Arrays.asList("approve"))).stream().findFirst().orElse(null);
        if (Objects.isNull(productRequire)) return;

        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            productRequire.getProductRequireItems().forEach(productRequireItem -> {
                if (servicePlanItem.getProduct().getId().equals(productRequireItem.getProduct().getId())){
                    servicePlanItem.setQtyRequire(Arith.add(servicePlanItem.getQtyRequire(),productRequireItem.getQtyRequire()));
                }
            });
        });
    }

    /**
     * 要货单审核时回写明细要货数量
     * @param productRequire
     */
    public void itemQtyRequire(ProductRequire productRequire){
        // 查询服务方案
        String id = productRequire.getSource();
        ServicePlan servicePlan = servicePlanRepository.findOne(id);
        if (Objects.isNull(servicePlan)) return;
        // 回写要货数量
        servicePlan.getServicePlanItems().forEach(servicePlanItem -> {
            productRequire.getProductRequireItems().forEach(productRequireItem -> {
                if (servicePlanItem.getProduct().getId().equals(productRequireItem.getProduct().getId())){
                    servicePlanItem.setQtyRequire(Arith.add(servicePlanItem.getQtyRequire(),productRequireItem.getQtyRequire()));
                }
            });
        });
        updateOnly(servicePlan);
    }

    /**\
     * 进入要货单菜单
     * @param re
     * @return
     */
    public ProductRequire toRequireFrom(SimpleRequest re){
        JSONObject jo = re.getJO();
        String id = jo.getString("id");
        if (id.contains("YH")) return productRequireRepository.findOne(id);

        ServicePlan servicePlan = servicePlanItemRepository.findOne(id).getServicePlan();
        JSONObject product = jo.getJSONObject("product");
        List<ProductRequireItem> items = new ArrayList<>();

        productRequireRepository.findAllBySource(servicePlan.getId())
                .stream()
                .map(ProductRequire::getProductRequireItems)
                .forEach(items::addAll);
        List<ProductRequire> productRequires = items.stream()
                .filter(productRequireItem -> productRequireItem.getProduct().getId().equals(product.getString("id")))
                .map(ProductRequireItem::getProductRequire)
                .collect(Collectors.toList());

        return productRequires.stream().findFirst().orElse(null);
    }

    /**
     * 进入领用单菜单
     * @param re
     * @return
     */
    public ProductReceive toProductReceiveFrom(SimpleRequest re){
        JSONObject jo = re.getJO();
        String id = jo.getString("id");
        if (id.contains("PL")) return productReceiveRepository.findOne(id);
        List<ProductReceive> byPlanItems = productReceiveRepository.findByPlanItems(Collections.singletonList(id));

        return byPlanItems.stream().findFirst().orElse(null);
    }

    /**
     * 从领用数量跳转至领用单（新增）
     * @param re
     * @return
     */
    public Map toProductReceiveCreate(SimpleRequest re){
        JSONObject jo = re.getJO();
        String id = jo.getString("id");
        Assert.isTrue(id != null, "无法获取明细编码！");
        ServicePlanItem servicePlanItem = servicePlanItemRepository.findOne(id);
        String servicePlanId = servicePlanItem.getServicePlan().getId();
        return MapUtil.mapper("toCreateFlag",true,"servicePlanId",servicePlanId);
    }

    public Object chooseRequireOrder(SimpleRequest re){
        JSONObject jo = re.getJO();
        JSONObject data = jo.getJSONObject("data");
        String id = data.getString("id");
        JSONObject node = data.getJSONObject("node");
        JSONObject product = node.getJSONObject("product");
        List<ProductRequireItem> items = new ArrayList<>();
        productRequireRepository.findAllBySource(id)
                .stream()
                .filter(productRequire -> productRequire.getState().equals("create"))
                .map(ProductRequire::getProductRequireItems)
                .forEach(items::addAll);
        List<Map> collect = items.stream()
                .filter(productRequireItem -> productRequireItem.getProduct().getId().equals(product.getString("id")))
                .map(ProductRequireItem::getProductRequire)
                .distinct()
                .map(productRequire -> mapper("id", productRequire.getId()))
                .collect(Collectors.toList());
        return MapUtil.mapper(
                "content", collect,
                "total", collect.size(),
                "size", collect.size()
        );
    }
    public Object chooseReceiveOrder(SimpleRequest re){
        JSONObject jo = re.getJO();
        JSONObject data = jo.getJSONObject("data");
        String id = data.getString("id");
        JSONObject node = data.getJSONObject("node");
        JSONObject product = node.getJSONObject("product");
        List<ProductReceive> byPlanItems = productReceiveRepository.findByPlanItems(Collections.singletonList(node.getString("id")));

        return MapUtil.mapper(
                "content", byPlanItems,
                "total", byPlanItems.size(),
                "size", byPlanItems.size()
        );
    }
    public void sendServeErrorToMongoDB(String planId, Exception e, String remark){
        if (false)return;
        Date date = new Date();
        if ("请分配销售员".equals(e.getMessage()))return;
        if ("已完成确认，请刷新界面".equals(e.getMessage()))return;
        String s = Tools.getAllStackTrace(e);
        Document document = new Document();
        document.put("servicePlanId", planId);
        document.put("errorMsg", e.getMessage());
        document.put("stackTrace", s);
        document.put("remark",remark);
        document.put("date",date.getTime());
        document.put("dateFormat",DateUtil.format(date,DateUtil.SHOW_DATETIME_FORMAT));
        mongoTemplate.getCollection(CONST_ERROR_MSG_COLLECTION_NAME).insertOne(document);
    }
    public Object inquiryPriceDetail(SimpleRequest request){
        JSONObject jo = request.getJO();
        String id = jo.getString("id");
        if (id==null)return null;
        ServicePlan servicePlan = servicePlanRepository.findOne(id);
        if (servicePlan==null)return null;
        Object invoke = this.invoke("sp.enquiry.result", mapper(
                "CAR_LICENSE", servicePlan.getFnCustomerExpand().getCarLicense(),
                "store", Arrays.asList(
                        SpringManager.getBean(StoreRepository.class).findByDept(servicePlan.getBelongDept()).getId()
                    ),"page",0,"size",50
                )
        );
        JSONObject page = (JSONObject) invoke;
        return page.getJSONArray("content");
    }
    public Object searchUnfinishedPlans(SimpleRequest request){
        Post post = SpringManager.getBean(PostRepository.class).findOne(request.getPostId());
        JSONObject resultJson = new JSONObject();
        List<ServicePlan> resultArray = new ArrayList<>();
        if (Objects.isNull(post)) {
            resultJson.put("plans",new JSONArray());
        }else {
            Dept dept = post.getDept();
            JSONObject jo = request.getJO();
            String carLicense = jo.getString("carLicense");
            List<ServicePlan> servicePlans = servicePlanRepository.findAll(JpaDsl.toCriteria("fnCustomerExpand.carLicense","EQ",carLicense,"belongDept","EQ",dept,"state","NIN",Arrays.asList("receivables","termination")));
            resultJson.put("plans",servicePlans);
            resultArray =servicePlans;
        }

        return resultJson;
    }
    public Object findServiceDetail(SimpleRequest request){
        JSONObject jo = request.getJO();
        String id = jo.getString("id");
        JSONObject fnCustomerExpandTemp = jo.getJSONObject("fnCustomerExpandTemp");
        JSONObject belongDept = jo.getJSONObject("belongDept");
        if (id ==null && fnCustomerExpandTemp==null)return null;
        if (id ==null && belongDept==null)return null;

        ServicePlan servicePlan = id==null?null:servicePlanRepository.findOne(id);
        if (servicePlan ==null && fnCustomerExpandTemp==null)return null;
        if (servicePlan ==null && belongDept==null)return null;

        String carLicense = fnCustomerExpandTemp==null?servicePlan.getFnCustomerExpand().getCarLicense():fnCustomerExpandTemp.getString("carLicense");
        String deptId = belongDept==null?servicePlan.getBelongDept().getId():belongDept.getString("id");
        String pickCarId = servicePlan==null?"":servicePlan.getPickCarId();
        //查找未结算服务记录
        JSONArray array = servicePlanDao.queryServerDetail(new JSONObject(mapper("CAR_LICENSE", carLicense, "DEPT_ID", deptId)));
        //查找本次接车记录
        array.addAll(servicePlanDao.queryServerDetailByPickCar(new JSONObject(mapper("CAR_LICENSE", carLicense, "DEPT_ID", deptId,"ID",pickCarId))));
        List<Object> collect = array.stream().distinct().collect(Collectors.toList());
        for (Object o : collect) {
            JSONObject jsonObject = (JSONObject) o;
            JSONArray data = servicePlanDao.queryServerDetailItems(jsonObject);
            jsonObject.put("servicePlanItems",data);
        }
        return collect;
    }

    /**
     * 修改接车单及时间
     * @param request
     * @return
     */
    private ServicePlan changeServerPickCarLog(SimpleRequest request){
        JSONArray ja = request.getJA();
        JSONObject jo = ja.getJSONObject(0);
        String planId = jo.getString("source");
        String mainPlan = jo.getString("mainPlan");
        String pickCarId = jo.getString("id");
        String createDateChar = jo.getString("createDate");
        String pickCarType = jo.getString("pickCarType");
        Date createDate = jo.getDate("createDate");
        String creator = jo.getString("creator");
        ServicePlan servicePlan = servicePlanRepository.findOne(planId);
//        PickUpCar pickUpCar = SpringManager.getBean(PickUpCarRepository.class).findOne(pickCarId);
        if (pickCarId.equals(servicePlan.getPickCarId()))return servicePlan;
        servicePlan.setPickCarId(pickCarId);
        servicePlan.setGetCarInfo(creator+" - "+createDateChar);
        servicePlan.setPickCarType(pickCarType);
        servicePlan.setPickCarDate(createDate);
        servicePlan.setPickCarName(creator);
        servicePlanRepository.saveAndFlush(servicePlan);
        PartyRole person = request.getPerson();
        User user =SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id",person.getId())).stream().findFirst().orElse(null);
        addServicePlanLogger(servicePlan,"修改接车单","接车单号: "+pickCarId+",\n接车人/时间: "+servicePlan.getGetCarInfo(),user);
        if (mainPlan==null)return servicePlan;
        if (!planId.equals(mainPlan))return servicePlanRepository.findOne(mainPlan);
        return servicePlan;
    }

    /**
     * 修改预估交车时间
     * @param request
     * @return
     */
    private ServicePlan changeEstimatedDeliveryDate(SimpleRequest request){
        JSONObject jo = request.getJO();
        String planId = jo.getString("id");
        Date estimatedDeliveryDate = jo.getDate("estimatedDeliveryDate");
        if (planId==null)return null;
        if (estimatedDeliveryDate==null)return null;
        estimatedDeliveryDate = DateUtil.dateToDate(estimatedDeliveryDate, DateUtil.SHOW_DATE_FORMAT);
        ServicePlan servicePlan = servicePlanRepository.findOne(planId);
        if (servicePlan==null)return null;
        if (servicePlan.getEstimatedDeliveryDate()!=null && estimatedDeliveryDate.getTime() == servicePlan.getEstimatedDeliveryDate().getTime())return servicePlan;
        servicePlan.setEstimatedDeliveryDate(estimatedDeliveryDate);
        servicePlanRepository.saveAndFlush(servicePlan);
        PartyRole person = request.getPerson();
        User user =SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id",person.getId())).stream().findFirst().orElse(null);
        addServicePlanLogger(servicePlan,"修改预计交车时间",DateUtil.format(estimatedDeliveryDate, DateUtil.SHOW_DATE_FORMAT),user);
        return servicePlan;
    }


    /**
     * 查询状态时条件过滤
     * @param request
     * @return
     */
    public Object searchChangeStateCondition(SimpleRequest request){
        JSONObject jo = request.getJO();
        JSONArray condition = jo.getJSONArray("condition");
        JSONArray newCondition = new JSONArray();
        for (Object o : condition) {
//            if (o instanceof HashMap)continue;//HashMap格式的一般是权限条件 前端条件是JSON
            if (!(o instanceof JSONObject)){
                newCondition.add(o);
                continue;
            }
            JSONObject jsonObject = (JSONObject) o;
            String operator = jsonObject.getString("operator");
            switch (jsonObject.getString("field")) {
                case "state":
                    if (operator.equals("EQ")) {
                        jsonObject.put("operator", "IN");
                        jsonObject.put("value", PLAN_SIMPLE_STATE.get(jsonObject.getString("value")));
                    } else {
                        throw new RuntimeException("未知操作符[" + operator + "]请补充");
                    }
                    newCondition.add(jsonObject);
                    break;
                case "terminal":
                    break;
                default:
                    newCondition.add(jsonObject);
            }
        }
        jo.put("condition",newCondition);
        return jo;
    }

    /**
     * app终止接口检查
     * @param request
     * @return
     */
    public Object appTerminateCheck(SimpleRequest request){
        JSONObject jo = request.getJO();
        Timestamp appTerminateCheck = SpringManager.getBean(TimestampRepository.class).findOne("appTerminateBeforeConfirm");
        if (appTerminateCheck==null)return jo;
        if ("1".equals(appTerminateCheck.getConditions())) {
            String servicePlanId = jo.getString("servicePlanId");
            ServicePlan service = servicePlanRepository.findOne(servicePlanId);
            if (service.getConfirmDate()==null){
                throw new RuntimeException("方案确认前请于ERP平台服务方案单操作终止");
            }
        }
        return jo;
    }

    /**
     * 检查是否能确认
     * @param request
     * @return
     */
    public Map checkCanBeConfirm(SimpleRequest request){
        JSONObject jo = request.getJO();
        String id = jo.getString("id");
        ServicePlan servicePlan = servicePlanRepository.findOne(id);
        if (servicePlan==null)return checkCanBeConfirmResult(false,"方案不存在","null");
        List<ServicePlanItem> servicePlanItems = servicePlan.getServicePlanItems();
        for (ServicePlanItem servicePlanItem : servicePlanItems) {
            if (servicePlanItem.getSupplier()!=null&&"004465".equals(servicePlanItem.getSupplier().getId())
                    &&servicePlanItem.getOldInquiryNumber()!=null&&!(servicePlanItem.getOldInquiryNumber().startsWith("WC"))){
                return checkCanBeConfirmResult(false,"商品:"+servicePlanItem.getProduct().getName()+",属于[现金外采],需发起[外采询价]审批通过后方可确认方案","externalInquiry");
            }
            if(servicePlanItem.isServiceState() && servicePlanItem.getMainSaler() == null)
                return checkCanBeConfirmResult(false,"请分配销售员","mainSaler");
        }
        return checkCanBeConfirmResult(true,"","success");
    }

    private Map checkCanBeConfirmResult(Boolean success,String info,String state){
        return mapper("success",success,"info",info,"state",state);
    }
}
